diff options
Diffstat (limited to 'drivers')
673 files changed, 15416 insertions, 10262 deletions
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index 2d8de2f8c1ed..cdd3136829f1 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -82,11 +82,11 @@ static SIMPLE_DEV_PM_OPS(acpi_ac_pm, NULL, acpi_ac_resume); #ifdef CONFIG_ACPI_PROCFS_POWER extern struct proc_dir_entry *acpi_lock_ac_dir(void); extern void *acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir); -static int acpi_ac_open_fs(struct inode *inode, struct file *file); #endif static int ac_sleep_before_get_state_ms; +static int ac_check_pmic = 1; static struct acpi_driver acpi_ac_driver = { .name = "ac", @@ -111,16 +111,6 @@ struct acpi_ac { #define to_acpi_ac(x) power_supply_get_drvdata(x) -#ifdef CONFIG_ACPI_PROCFS_POWER -static const struct file_operations acpi_ac_fops = { - .owner = THIS_MODULE, - .open = acpi_ac_open_fs, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; -#endif - /* -------------------------------------------------------------------------- AC Adapter Management -------------------------------------------------------------------------- */ @@ -209,11 +199,6 @@ static int acpi_ac_seq_show(struct seq_file *seq, void *offset) return 0; } -static int acpi_ac_open_fs(struct inode *inode, struct file *file) -{ - return single_open(file, acpi_ac_seq_show, PDE_DATA(inode)); -} - static int acpi_ac_add_fs(struct acpi_ac *ac) { struct proc_dir_entry *entry = NULL; @@ -228,9 +213,8 @@ static int acpi_ac_add_fs(struct acpi_ac *ac) } /* 'state' [R] */ - entry = proc_create_data(ACPI_AC_FILE_STATE, - S_IRUGO, acpi_device_dir(ac->device), - &acpi_ac_fops, ac); + entry = proc_create_single_data(ACPI_AC_FILE_STATE, S_IRUGO, + acpi_device_dir(ac->device), acpi_ac_seq_show, ac); if (!entry) return -ENODEV; return 0; @@ -310,21 +294,43 @@ static int acpi_ac_battery_notify(struct notifier_block *nb, return NOTIFY_OK; } -static int thinkpad_e530_quirk(const struct dmi_system_id *d) +static int __init thinkpad_e530_quirk(const struct dmi_system_id *d) { ac_sleep_before_get_state_ms = 1000; return 0; } -static const struct dmi_system_id ac_dmi_table[] = { +static int __init ac_do_not_check_pmic_quirk(const struct dmi_system_id *d) +{ + ac_check_pmic = 0; + return 0; +} + +static const struct dmi_system_id ac_dmi_table[] __initconst = { { + /* Thinkpad e530 */ .callback = thinkpad_e530_quirk, - .ident = "thinkpad e530", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "32597CG"), }, }, + { + /* ECS EF20EA */ + .callback = ac_do_not_check_pmic_quirk, + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "EF20EA"), + }, + }, + { + /* Lenovo Ideapad Miix 320 */ + .callback = ac_do_not_check_pmic_quirk, + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "80XF"), + DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Lenovo MIIX 320-10ICR"), + }, + }, {}, }; @@ -384,7 +390,6 @@ end: kfree(ac); } - dmi_check_system(ac_dmi_table); return result; } @@ -442,13 +447,17 @@ static int __init acpi_ac_init(void) if (acpi_disabled) return -ENODEV; - for (i = 0; i < ARRAY_SIZE(acpi_ac_blacklist); i++) - if (acpi_dev_present(acpi_ac_blacklist[i].hid, "1", - acpi_ac_blacklist[i].hrv)) { - pr_info(PREFIX "AC: found native %s PMIC, not loading\n", - acpi_ac_blacklist[i].hid); - return -ENODEV; - } + dmi_check_system(ac_dmi_table); + + if (ac_check_pmic) { + for (i = 0; i < ARRAY_SIZE(acpi_ac_blacklist); i++) + if (acpi_dev_present(acpi_ac_blacklist[i].hid, "1", + acpi_ac_blacklist[i].hrv)) { + pr_info(PREFIX "AC: found native %s PMIC, not loading\n", + acpi_ac_blacklist[i].hid); + return -ENODEV; + } + } #ifdef CONFIG_ACPI_PROCFS_POWER acpi_ac_dir = acpi_lock_ac_dir(); diff --git a/drivers/acpi/acpi_apd.c b/drivers/acpi/acpi_apd.c index d553b0087947..2664452fa112 100644 --- a/drivers/acpi/acpi_apd.c +++ b/drivers/acpi/acpi_apd.c @@ -11,6 +11,7 @@ */ #include <linux/clk-provider.h> +#include <linux/platform_data/clk-st.h> #include <linux/platform_device.h> #include <linux/pm_domain.h> #include <linux/clkdev.h> @@ -72,6 +73,47 @@ static int acpi_apd_setup(struct apd_private_data *pdata) } #ifdef CONFIG_X86_AMD_PLATFORM_DEVICE + +static int misc_check_res(struct acpi_resource *ares, void *data) +{ + struct resource res; + + return !acpi_dev_resource_memory(ares, &res); +} + +static int st_misc_setup(struct apd_private_data *pdata) +{ + struct acpi_device *adev = pdata->adev; + struct platform_device *clkdev; + struct st_clk_data *clk_data; + struct resource_entry *rentry; + struct list_head resource_list; + int ret; + + clk_data = devm_kzalloc(&adev->dev, sizeof(*clk_data), GFP_KERNEL); + if (!clk_data) + return -ENOMEM; + + INIT_LIST_HEAD(&resource_list); + ret = acpi_dev_get_resources(adev, &resource_list, misc_check_res, + NULL); + if (ret < 0) + return -ENOENT; + + list_for_each_entry(rentry, &resource_list, node) { + clk_data->base = devm_ioremap(&adev->dev, rentry->res->start, + resource_size(rentry->res)); + break; + } + + acpi_dev_free_resource_list(&resource_list); + + clkdev = platform_device_register_data(&adev->dev, "clk-st", + PLATFORM_DEVID_NONE, clk_data, + sizeof(*clk_data)); + return PTR_ERR_OR_ZERO(clkdev); +} + static const struct apd_device_desc cz_i2c_desc = { .setup = acpi_apd_setup, .fixed_clk_rate = 133000000, @@ -94,6 +136,10 @@ static const struct apd_device_desc cz_uart_desc = { .fixed_clk_rate = 48000000, .properties = uart_properties, }; + +static const struct apd_device_desc st_misc_desc = { + .setup = st_misc_setup, +}; #endif #ifdef CONFIG_ARM64 @@ -179,6 +225,7 @@ static const struct acpi_device_id acpi_apd_device_ids[] = { { "AMD0020", APD_ADDR(cz_uart_desc) }, { "AMDI0020", APD_ADDR(cz_uart_desc) }, { "AMD0030", }, + { "AMD0040", APD_ADDR(st_misc_desc)}, #endif #ifdef CONFIG_ARM64 { "APMC0D0F", APD_ADDR(xgene_i2c_desc) }, diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 2bcffec8dbf0..cb6ac5c65c2e 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -69,6 +69,10 @@ ACPI_MODULE_NAME("acpi_lpss"); #define LPSS_SAVE_CTX BIT(4) #define LPSS_NO_D3_DELAY BIT(5) +/* Crystal Cove PMIC shares same ACPI ID between different platforms */ +#define BYT_CRC_HRV 2 +#define CHT_CRC_HRV 3 + struct lpss_private_data; struct lpss_device_desc { @@ -162,7 +166,7 @@ static void byt_pwm_setup(struct lpss_private_data *pdata) if (!adev->pnp.unique_id || strcmp(adev->pnp.unique_id, "1")) return; - if (!acpi_dev_present("INT33FD", NULL, -1)) + if (!acpi_dev_present("INT33FD", NULL, BYT_CRC_HRV)) pwm_add_table(byt_pwm_lookup, ARRAY_SIZE(byt_pwm_lookup)); } diff --git a/drivers/acpi/acpi_watchdog.c b/drivers/acpi/acpi_watchdog.c index 4bde16fb97d8..95600309ce42 100644 --- a/drivers/acpi/acpi_watchdog.c +++ b/drivers/acpi/acpi_watchdog.c @@ -12,35 +12,51 @@ #define pr_fmt(fmt) "ACPI: watchdog: " fmt #include <linux/acpi.h> -#include <linux/dmi.h> #include <linux/ioport.h> #include <linux/platform_device.h> #include "internal.h" -static const struct dmi_system_id acpi_watchdog_skip[] = { - { - /* - * On Lenovo Z50-70 there are two issues with the WDAT - * table. First some of the instructions use RTC SRAM - * to store persistent information. This does not work well - * with Linux RTC driver. Second, more important thing is - * that the instructions do not actually reset the system. - * - * On this particular system iTCO_wdt seems to work just - * fine so we prefer that over WDAT for now. - * - * See also https://bugzilla.kernel.org/show_bug.cgi?id=199033. - */ - .ident = "Lenovo Z50-70", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_NAME, "20354"), - DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Z50-70"), - }, - }, - {} -}; +#ifdef CONFIG_RTC_MC146818_LIB +#include <linux/mc146818rtc.h> + +/* + * There are several systems where the WDAT table is accessing RTC SRAM to + * store persistent information. This does not work well with the Linux RTC + * driver so on those systems we skip WDAT driver and prefer iTCO_wdt + * instead. + * + * See also https://bugzilla.kernel.org/show_bug.cgi?id=199033. + */ +static bool acpi_watchdog_uses_rtc(const struct acpi_table_wdat *wdat) +{ + const struct acpi_wdat_entry *entries; + int i; + + entries = (struct acpi_wdat_entry *)(wdat + 1); + for (i = 0; i < wdat->entries; i++) { + const struct acpi_generic_address *gas; + + gas = &entries[i].register_region; + if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO) { + switch (gas->address) { + case RTC_PORT(0): + case RTC_PORT(1): + case RTC_PORT(2): + case RTC_PORT(3): + return true; + } + } + } + + return false; +} +#else +static bool acpi_watchdog_uses_rtc(const struct acpi_table_wdat *wdat) +{ + return false; +} +#endif static const struct acpi_table_wdat *acpi_watchdog_get_wdat(void) { @@ -50,9 +66,6 @@ static const struct acpi_table_wdat *acpi_watchdog_get_wdat(void) if (acpi_disabled) return NULL; - if (dmi_check_system(acpi_watchdog_skip)) - return NULL; - status = acpi_get_table(ACPI_SIG_WDAT, 0, (struct acpi_table_header **)&wdat); if (ACPI_FAILURE(status)) { @@ -60,6 +73,11 @@ static const struct acpi_table_wdat *acpi_watchdog_get_wdat(void) return NULL; } + if (acpi_watchdog_uses_rtc(wdat)) { + pr_info("Skipping WDAT on this system because it uses RTC SRAM\n"); + return NULL; + } + return wdat; } diff --git a/drivers/acpi/acpica/acapps.h b/drivers/acpi/acpica/acapps.h index a2a85122fafe..5a9c2febc0fb 100644 --- a/drivers/acpi/acpica/acapps.h +++ b/drivers/acpi/acpica/acapps.h @@ -143,6 +143,8 @@ acpi_status fl_split_input_pathname(char *input_path, char **out_directory_path, char **out_filename); +char *fl_get_file_basename(char *file_pathname); + char *ad_generate_filename(char *prefix, char *table_id); void diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 0bc550072a21..1e6204518496 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -82,7 +82,7 @@ ACPI_GLOBAL(u8, acpi_gbl_global_lock_pending); * interrupt level */ ACPI_GLOBAL(acpi_spinlock, acpi_gbl_gpe_lock); /* For GPE data structs and registers */ -ACPI_GLOBAL(acpi_spinlock, acpi_gbl_hardware_lock); /* For ACPI H/W except GPE registers */ +ACPI_GLOBAL(acpi_raw_spinlock, acpi_gbl_hardware_lock); /* For ACPI H/W except GPE registers */ ACPI_GLOBAL(acpi_spinlock, acpi_gbl_reference_count_lock); /* Mutex for _OSI support */ diff --git a/drivers/acpi/acpica/dbnames.c b/drivers/acpi/acpica/dbnames.c index 170802c62179..dc94de91033e 100644 --- a/drivers/acpi/acpica/dbnames.c +++ b/drivers/acpi/acpica/dbnames.c @@ -189,9 +189,15 @@ void acpi_db_dump_namespace(char *start_arg, char *depth_arg) } acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT); - acpi_os_printf("ACPI Namespace (from %4.4s (%p) subtree):\n", - ((struct acpi_namespace_node *)subtree_entry)->name. - ascii, subtree_entry); + + if (((struct acpi_namespace_node *)subtree_entry)->parent) { + acpi_os_printf("ACPI Namespace (from %4.4s (%p) subtree):\n", + ((struct acpi_namespace_node *)subtree_entry)-> + name.ascii, subtree_entry); + } else { + acpi_os_printf("ACPI Namespace (from %s):\n", + ACPI_NAMESPACE_ROOT); + } /* Display the subtree */ diff --git a/drivers/acpi/acpica/dbtest.c b/drivers/acpi/acpica/dbtest.c index 3892680a5258..8a5462439a97 100644 --- a/drivers/acpi/acpica/dbtest.c +++ b/drivers/acpi/acpica/dbtest.c @@ -30,6 +30,8 @@ acpi_db_test_buffer_type(struct acpi_namespace_node *node, u32 bit_length); static acpi_status acpi_db_test_string_type(struct acpi_namespace_node *node, u32 byte_length); +static acpi_status acpi_db_test_package_type(struct acpi_namespace_node *node); + static acpi_status acpi_db_read_from_object(struct acpi_namespace_node *node, acpi_object_type expected_type, @@ -273,6 +275,11 @@ acpi_db_test_one_object(acpi_handle obj_handle, bit_length = byte_length * 8; break; + case ACPI_TYPE_PACKAGE: + + local_type = ACPI_TYPE_PACKAGE; + break; + case ACPI_TYPE_FIELD_UNIT: case ACPI_TYPE_BUFFER_FIELD: case ACPI_TYPE_LOCAL_REGION_FIELD: @@ -305,6 +312,7 @@ acpi_db_test_one_object(acpi_handle obj_handle, acpi_os_printf("%14s: %4.4s", acpi_ut_get_type_name(node->type), node->name.ascii); + if (!obj_desc) { acpi_os_printf(" Ignoring, no attached object\n"); return (AE_OK); @@ -322,14 +330,13 @@ acpi_db_test_one_object(acpi_handle obj_handle, case ACPI_ADR_SPACE_SYSTEM_MEMORY: case ACPI_ADR_SPACE_SYSTEM_IO: case ACPI_ADR_SPACE_PCI_CONFIG: - case ACPI_ADR_SPACE_EC: break; default: acpi_os_printf - (" %s space is not supported [%4.4s]\n", + (" %s space is not supported in this command [%4.4s]\n", acpi_ut_get_region_name(region_obj->region. space_id), region_obj->region.node->name.ascii); @@ -359,6 +366,11 @@ acpi_db_test_one_object(acpi_handle obj_handle, status = acpi_db_test_buffer_type(node, bit_length); break; + case ACPI_TYPE_PACKAGE: + + status = acpi_db_test_package_type(node); + break; + default: acpi_os_printf(" Ignoring, type not implemented (%2.2X)", @@ -366,6 +378,13 @@ acpi_db_test_one_object(acpi_handle obj_handle, break; } + /* Exit on error, but don't abort the namespace walk */ + + if (ACPI_FAILURE(status)) { + status = AE_OK; + goto exit; + } + switch (node->type) { case ACPI_TYPE_LOCAL_REGION_FIELD: @@ -373,12 +392,14 @@ acpi_db_test_one_object(acpi_handle obj_handle, acpi_os_printf(" (%s)", acpi_ut_get_region_name(region_obj->region. space_id)); + break; default: break; } +exit: acpi_os_printf("\n"); return (status); } @@ -431,7 +452,6 @@ acpi_db_test_integer_type(struct acpi_namespace_node *node, u32 bit_length) if (temp1->integer.value == value_to_write) { value_to_write = 0; } - /* Write a new value */ write_value.type = ACPI_TYPE_INTEGER; @@ -708,6 +728,35 @@ exit: /******************************************************************************* * + * FUNCTION: acpi_db_test_package_type + * + * PARAMETERS: node - Parent NS node for the object + * + * RETURN: Status + * + * DESCRIPTION: Test read for a Package object. + * + ******************************************************************************/ + +static acpi_status acpi_db_test_package_type(struct acpi_namespace_node *node) +{ + union acpi_object *temp1 = NULL; + acpi_status status; + + /* Read the original value */ + + status = acpi_db_read_from_object(node, ACPI_TYPE_PACKAGE, &temp1); + if (ACPI_FAILURE(status)) { + return (status); + } + + acpi_os_printf(" %8.8X Elements", temp1->package.count); + acpi_os_free(temp1); + return (status); +} + +/******************************************************************************* + * * FUNCTION: acpi_db_read_from_object * * PARAMETERS: node - Parent NS node for the object @@ -746,8 +795,8 @@ acpi_db_read_from_object(struct acpi_namespace_node *node, acpi_gbl_method_executing = TRUE; status = acpi_evaluate_object(read_handle, NULL, ¶m_objects, &return_obj); - acpi_gbl_method_executing = FALSE; + acpi_gbl_method_executing = FALSE; if (ACPI_FAILURE(status)) { acpi_os_printf("Could not read from object, %s", acpi_format_exception(status)); @@ -760,6 +809,7 @@ acpi_db_read_from_object(struct acpi_namespace_node *node, case ACPI_TYPE_INTEGER: case ACPI_TYPE_BUFFER: case ACPI_TYPE_STRING: + case ACPI_TYPE_PACKAGE: /* * Did we receive the type we wanted? Most important for the * Integer/Buffer case (when a field is larger than an Integer, @@ -771,6 +821,7 @@ acpi_db_read_from_object(struct acpi_namespace_node *node, acpi_ut_get_type_name(expected_type), acpi_ut_get_type_name(ret_value->type)); + acpi_os_free(return_obj.pointer); return (AE_TYPE); } diff --git a/drivers/acpi/acpica/dswscope.c b/drivers/acpi/acpica/dswscope.c index d1422f984f6e..7592176a8fa2 100644 --- a/drivers/acpi/acpica/dswscope.c +++ b/drivers/acpi/acpica/dswscope.c @@ -115,7 +115,7 @@ acpi_ds_scope_stack_push(struct acpi_namespace_node *node, acpi_ut_get_type_name(old_scope_info-> common.value))); } else { - ACPI_DEBUG_PRINT_RAW((ACPI_DB_EXEC, "[\\___] (%s)", "ROOT")); + ACPI_DEBUG_PRINT_RAW((ACPI_DB_EXEC, ACPI_NAMESPACE_ROOT)); } ACPI_DEBUG_PRINT_RAW((ACPI_DB_EXEC, @@ -166,14 +166,14 @@ acpi_status acpi_ds_scope_stack_pop(struct acpi_walk_state *walk_state) new_scope_info = walk_state->scope_info; if (new_scope_info) { - ACPI_DEBUG_PRINT_RAW((ACPI_DB_EXEC, - "[%4.4s] (%s)\n", + ACPI_DEBUG_PRINT_RAW((ACPI_DB_EXEC, "[%4.4s] (%s)\n", acpi_ut_get_node_name(new_scope_info-> scope.node), acpi_ut_get_type_name(new_scope_info-> common.value))); } else { - ACPI_DEBUG_PRINT_RAW((ACPI_DB_EXEC, "[\\___] (ROOT)\n")); + ACPI_DEBUG_PRINT_RAW((ACPI_DB_EXEC, "%s\n", + ACPI_NAMESPACE_ROOT)); } acpi_ut_delete_generic_state(scope_info); diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index abbd59063906..e10fec99a182 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c @@ -634,6 +634,12 @@ acpi_ev_detect_gpe(struct acpi_namespace_node *gpe_device, flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); + if (!gpe_event_info) { + gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); + if (!gpe_event_info) + goto error_exit; + } + /* Get the info block for the entire GPE register */ gpe_register_info = gpe_event_info->register_info; diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c index c80e3bdf4805..b2d5f66cc1b0 100644 --- a/drivers/acpi/acpica/evxfgpe.c +++ b/drivers/acpi/acpica/evxfgpe.c @@ -639,6 +639,28 @@ ACPI_EXPORT_SYMBOL(acpi_get_gpe_status) /******************************************************************************* * + * FUNCTION: acpi_gispatch_gpe + * + * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 + * gpe_number - GPE level within the GPE block + * + * RETURN: None + * + * DESCRIPTION: Detect and dispatch a General Purpose Event to either a function + * (e.g. EC) or method (e.g. _Lxx/_Exx) handler. + * + ******************************************************************************/ +void acpi_dispatch_gpe(acpi_handle gpe_device, u32 gpe_number) +{ + ACPI_FUNCTION_TRACE(acpi_dispatch_gpe); + + acpi_ev_detect_gpe(gpe_device, NULL, gpe_number); +} + +ACPI_EXPORT_SYMBOL(acpi_dispatch_gpe) + +/******************************************************************************* + * * FUNCTION: acpi_finish_gpe * * PARAMETERS: gpe_device - Namespace node for the GPE Block diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c index 27a86ad55b58..3de794bcf8fa 100644 --- a/drivers/acpi/acpica/hwregs.c +++ b/drivers/acpi/acpica/hwregs.c @@ -390,14 +390,14 @@ acpi_status acpi_hw_clear_acpi_status(void) ACPI_BITMASK_ALL_FIXED_STATUS, ACPI_FORMAT_UINT64(acpi_gbl_xpm1a_status.address))); - lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock); + lock_flags = acpi_os_acquire_raw_lock(acpi_gbl_hardware_lock); /* Clear the fixed events in PM1 A/B */ status = acpi_hw_register_write(ACPI_REGISTER_PM1_STATUS, ACPI_BITMASK_ALL_FIXED_STATUS); - acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags); + acpi_os_release_raw_lock(acpi_gbl_hardware_lock, lock_flags); if (ACPI_FAILURE(status)) { goto exit; diff --git a/drivers/acpi/acpica/hwxface.c b/drivers/acpi/acpica/hwxface.c index 5d1396870bd0..6e39a771a56e 100644 --- a/drivers/acpi/acpica/hwxface.c +++ b/drivers/acpi/acpica/hwxface.c @@ -227,7 +227,7 @@ acpi_status acpi_write_bit_register(u32 register_id, u32 value) return_ACPI_STATUS(AE_BAD_PARAMETER); } - lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock); + lock_flags = acpi_os_acquire_raw_lock(acpi_gbl_hardware_lock); /* * At this point, we know that the parent register is one of the @@ -288,7 +288,7 @@ acpi_status acpi_write_bit_register(u32 register_id, u32 value) unlock_and_exit: - acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags); + acpi_os_release_raw_lock(acpi_gbl_hardware_lock, lock_flags); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/rsdump.c b/drivers/acpi/acpica/rsdump.c index b12a0b1cd9ce..6601e71b45e3 100644 --- a/drivers/acpi/acpica/rsdump.c +++ b/drivers/acpi/acpica/rsdump.c @@ -539,7 +539,7 @@ static void acpi_rs_out_title(const char *title) static void acpi_rs_dump_byte_list(u16 length, u8 * data) { - u8 i; + u16 i; for (i = 0; i < length; i++) { acpi_os_printf("%25s%2.2X : %2.2X\n", "Byte", i, data[i]); diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index c5085b7ae8c9..5f8e7b561c90 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -88,7 +88,7 @@ acpi_tb_install_table_with_override(struct acpi_table_desc *new_table_desc, * DESCRIPTION: This function is called to verify and install an ACPI table. * When this function is called by "Load" or "LoadTable" opcodes, * or by acpi_load_table() API, the "Reload" parameter is set. - * After sucessfully returning from this function, table is + * After successfully returning from this function, table is * "INSTALLED" but not "VALIDATED". * ******************************************************************************/ diff --git a/drivers/acpi/acpica/utbuffer.c b/drivers/acpi/acpica/utbuffer.c index 148aeb84e561..fffa6f5ae59e 100644 --- a/drivers/acpi/acpica/utbuffer.c +++ b/drivers/acpi/acpica/utbuffer.c @@ -53,7 +53,7 @@ void acpi_ut_dump_buffer(u8 *buffer, u32 count, u32 display, u32 base_offset) /* Print current offset */ - acpi_os_printf("%6.4X: ", (base_offset + i)); + acpi_os_printf("%8.4X: ", (base_offset + i)); /* Print 16 hex chars */ @@ -219,7 +219,7 @@ acpi_ut_dump_buffer_to_file(ACPI_FILE file, /* Print current offset */ - fprintf(file, "%6.4X: ", (base_offset + i)); + fprintf(file, "%8.4X: ", (base_offset + i)); /* Print 16 hex chars */ diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c index d2d93e388f40..2e465e6a0ab6 100644 --- a/drivers/acpi/acpica/utmutex.c +++ b/drivers/acpi/acpica/utmutex.c @@ -52,7 +52,7 @@ acpi_status acpi_ut_mutex_initialize(void) return_ACPI_STATUS (status); } - status = acpi_os_create_lock (&acpi_gbl_hardware_lock); + status = acpi_os_create_raw_lock(&acpi_gbl_hardware_lock); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -109,7 +109,7 @@ void acpi_ut_mutex_terminate(void) /* Delete the spinlocks */ acpi_os_delete_lock(acpi_gbl_gpe_lock); - acpi_os_delete_lock(acpi_gbl_hardware_lock); + acpi_os_delete_raw_lock(acpi_gbl_hardware_lock); acpi_os_delete_lock(acpi_gbl_reference_count_lock); /* Delete the reader/writer lock */ diff --git a/drivers/acpi/acpica/utobject.c b/drivers/acpi/acpica/utobject.c index 5b78fe08d7d7..ae6d8cc18cec 100644 --- a/drivers/acpi/acpica/utobject.c +++ b/drivers/acpi/acpica/utobject.c @@ -8,6 +8,7 @@ *****************************************************************************/ #include <acpi/acpi.h> +#include <linux/kmemleak.h> #include "accommon.h" #include "acnamesp.h" @@ -70,6 +71,7 @@ union acpi_operand_object *acpi_ut_create_internal_object_dbg(const char if (!object) { return_PTR(NULL); } + kmemleak_not_leak(object); switch (type) { case ACPI_TYPE_REGION: diff --git a/drivers/acpi/acpica/utprint.c b/drivers/acpi/acpica/utprint.c index 35ffd8d51c65..a98c334c3bb7 100644 --- a/drivers/acpi/acpica/utprint.c +++ b/drivers/acpi/acpica/utprint.c @@ -470,6 +470,7 @@ int vsnprintf(char *string, acpi_size size, const char *format, va_list args) case 'X': type |= ACPI_FORMAT_UPPER; + /* FALLTHROUGH */ case 'x': diff --git a/drivers/acpi/acpica/utstring.c b/drivers/acpi/acpica/utstring.c index bd57a77bbcb2..5bef0b059406 100644 --- a/drivers/acpi/acpica/utstring.c +++ b/drivers/acpi/acpica/utstring.c @@ -141,7 +141,7 @@ void acpi_ut_repair_name(char *name) * Special case for the root node. This can happen if we get an * error during the execution of module-level code. */ - if (ACPI_COMPARE_NAME(name, "\\___")) { + if (ACPI_COMPARE_NAME(name, ACPI_ROOT_PATHNAME)) { return; } diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index bdb24d636d9a..b0113a5802a3 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -74,6 +74,8 @@ static async_cookie_t async_cookie; static bool battery_driver_registered; static int battery_bix_broken_package; static int battery_notification_delay_ms; +static int battery_ac_is_broken; +static int battery_check_pmic = 1; static unsigned int cache_time = 1000; module_param(cache_time, uint, 0644); MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); @@ -81,14 +83,6 @@ MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); #ifdef CONFIG_ACPI_PROCFS_POWER extern struct proc_dir_entry *acpi_lock_battery_dir(void); extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); - -enum acpi_battery_files { - info_tag = 0, - state_tag, - alarm_tag, - ACPI_BATTERY_NUMFILES, -}; - #endif static const struct acpi_device_id battery_device_ids[] = { @@ -215,6 +209,20 @@ static bool acpi_battery_is_degraded(struct acpi_battery *battery) battery->full_charge_capacity < battery->design_capacity; } +static int acpi_battery_handle_discharging(struct acpi_battery *battery) +{ + /* + * Some devices wrongly report discharging if the battery's charge level + * was above the device's start charging threshold atm the AC adapter + * was plugged in and the device thus did not start a new charge cycle. + */ + if ((battery_ac_is_broken || power_supply_is_system_supplied()) && + battery->rate_now == 0) + return POWER_SUPPLY_STATUS_NOT_CHARGING; + + return POWER_SUPPLY_STATUS_DISCHARGING; +} + static int acpi_battery_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) @@ -230,7 +238,7 @@ static int acpi_battery_get_property(struct power_supply *psy, switch (psp) { case POWER_SUPPLY_PROP_STATUS: if (battery->state & ACPI_BATTERY_STATE_DISCHARGING) - val->intval = POWER_SUPPLY_STATUS_DISCHARGING; + val->intval = acpi_battery_handle_discharging(battery); else if (battery->state & ACPI_BATTERY_STATE_CHARGING) val->intval = POWER_SUPPLY_STATUS_CHARGING; else if (acpi_battery_is_charged(battery)) @@ -985,9 +993,10 @@ static const char *acpi_battery_units(const struct acpi_battery *battery) "mA" : "mW"; } -static int acpi_battery_print_info(struct seq_file *seq, int result) +static int acpi_battery_info_proc_show(struct seq_file *seq, void *offset) { struct acpi_battery *battery = seq->private; + int result = acpi_battery_update(battery, false); if (result) goto end; @@ -1041,9 +1050,10 @@ static int acpi_battery_print_info(struct seq_file *seq, int result) return result; } -static int acpi_battery_print_state(struct seq_file *seq, int result) +static int acpi_battery_state_proc_show(struct seq_file *seq, void *offset) { struct acpi_battery *battery = seq->private; + int result = acpi_battery_update(battery, false); if (result) goto end; @@ -1088,9 +1098,10 @@ static int acpi_battery_print_state(struct seq_file *seq, int result) return result; } -static int acpi_battery_print_alarm(struct seq_file *seq, int result) +static int acpi_battery_alarm_proc_show(struct seq_file *seq, void *offset) { struct acpi_battery *battery = seq->private; + int result = acpi_battery_update(battery, false); if (result) goto end; @@ -1142,82 +1153,22 @@ static ssize_t acpi_battery_write_alarm(struct file *file, return result; } -typedef int(*print_func)(struct seq_file *seq, int result); - -static print_func acpi_print_funcs[ACPI_BATTERY_NUMFILES] = { - acpi_battery_print_info, - acpi_battery_print_state, - acpi_battery_print_alarm, -}; - -static int acpi_battery_read(int fid, struct seq_file *seq) +static int acpi_battery_alarm_proc_open(struct inode *inode, struct file *file) { - struct acpi_battery *battery = seq->private; - int result = acpi_battery_update(battery, false); - return acpi_print_funcs[fid](seq, result); -} - -#define DECLARE_FILE_FUNCTIONS(_name) \ -static int acpi_battery_read_##_name(struct seq_file *seq, void *offset) \ -{ \ - return acpi_battery_read(_name##_tag, seq); \ -} \ -static int acpi_battery_##_name##_open_fs(struct inode *inode, struct file *file) \ -{ \ - return single_open(file, acpi_battery_read_##_name, PDE_DATA(inode)); \ + return single_open(file, acpi_battery_alarm_proc_show, PDE_DATA(inode)); } -DECLARE_FILE_FUNCTIONS(info); -DECLARE_FILE_FUNCTIONS(state); -DECLARE_FILE_FUNCTIONS(alarm); - -#undef DECLARE_FILE_FUNCTIONS - -#define FILE_DESCRIPTION_RO(_name) \ - { \ - .name = __stringify(_name), \ - .mode = S_IRUGO, \ - .ops = { \ - .open = acpi_battery_##_name##_open_fs, \ - .read = seq_read, \ - .llseek = seq_lseek, \ - .release = single_release, \ - .owner = THIS_MODULE, \ - }, \ - } - -#define FILE_DESCRIPTION_RW(_name) \ - { \ - .name = __stringify(_name), \ - .mode = S_IFREG | S_IRUGO | S_IWUSR, \ - .ops = { \ - .open = acpi_battery_##_name##_open_fs, \ - .read = seq_read, \ - .llseek = seq_lseek, \ - .write = acpi_battery_write_##_name, \ - .release = single_release, \ - .owner = THIS_MODULE, \ - }, \ - } - -static const struct battery_file { - struct file_operations ops; - umode_t mode; - const char *name; -} acpi_battery_file[] = { - FILE_DESCRIPTION_RO(info), - FILE_DESCRIPTION_RO(state), - FILE_DESCRIPTION_RW(alarm), +static const struct file_operations acpi_battery_alarm_fops = { + .owner = THIS_MODULE, + .open = acpi_battery_alarm_proc_open, + .read = seq_read, + .write = acpi_battery_write_alarm, + .llseek = seq_lseek, + .release = single_release, }; -#undef FILE_DESCRIPTION_RO -#undef FILE_DESCRIPTION_RW - static int acpi_battery_add_fs(struct acpi_device *device) { - struct proc_dir_entry *entry = NULL; - int i; - printk(KERN_WARNING PREFIX "Deprecated procfs I/F for battery is loaded," " please retry with CONFIG_ACPI_PROCFS_POWER cleared\n"); if (!acpi_device_dir(device)) { @@ -1227,28 +1178,24 @@ static int acpi_battery_add_fs(struct acpi_device *device) return -ENODEV; } - for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) { - entry = proc_create_data(acpi_battery_file[i].name, - acpi_battery_file[i].mode, - acpi_device_dir(device), - &acpi_battery_file[i].ops, - acpi_driver_data(device)); - if (!entry) - return -ENODEV; - } + if (!proc_create_single_data("info", S_IRUGO, acpi_device_dir(device), + acpi_battery_info_proc_show, acpi_driver_data(device))) + return -ENODEV; + if (!proc_create_single_data("state", S_IRUGO, acpi_device_dir(device), + acpi_battery_state_proc_show, acpi_driver_data(device))) + return -ENODEV; + if (!proc_create_data("alarm", S_IFREG | S_IRUGO | S_IWUSR, + acpi_device_dir(device), &acpi_battery_alarm_fops, + acpi_driver_data(device))) + return -ENODEV; return 0; } static void acpi_battery_remove_fs(struct acpi_device *device) { - int i; if (!acpi_device_dir(device)) return; - for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) - remove_proc_entry(acpi_battery_file[i].name, - acpi_device_dir(device)); - - remove_proc_entry(acpi_device_bid(device), acpi_battery_dir); + remove_proc_subtree(acpi_device_bid(device), acpi_battery_dir); acpi_device_dir(device) = NULL; } @@ -1332,23 +1279,64 @@ battery_notification_delay_quirk(const struct dmi_system_id *d) return 0; } +static int __init +battery_ac_is_broken_quirk(const struct dmi_system_id *d) +{ + battery_ac_is_broken = 1; + return 0; +} + +static int __init +battery_do_not_check_pmic_quirk(const struct dmi_system_id *d) +{ + battery_check_pmic = 0; + return 0; +} + static const struct dmi_system_id bat_dmi_table[] __initconst = { { + /* NEC LZ750/LS */ .callback = battery_bix_broken_package_quirk, - .ident = "NEC LZ750/LS", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "NEC"), DMI_MATCH(DMI_PRODUCT_NAME, "PC-LZ750LS"), }, }, { + /* Acer Aspire V5-573G */ .callback = battery_notification_delay_quirk, - .ident = "Acer Aspire V5-573G", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire V5-573G"), }, }, + { + /* Point of View mobii wintab p800w */ + .callback = battery_ac_is_broken_quirk, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), + DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"), + DMI_MATCH(DMI_BIOS_VERSION, "3BAIR1013"), + /* Above matches are too generic, add bios-date match */ + DMI_MATCH(DMI_BIOS_DATE, "08/22/2014"), + }, + }, + { + /* ECS EF20EA */ + .callback = battery_do_not_check_pmic_quirk, + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "EF20EA"), + }, + }, + { + /* Lenovo Ideapad Miix 320 */ + .callback = battery_do_not_check_pmic_quirk, + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "80XF"), + DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Lenovo MIIX 320-10ICR"), + }, + }, {}, }; @@ -1488,16 +1476,18 @@ static void __init acpi_battery_init_async(void *unused, async_cookie_t cookie) unsigned int i; int result; - for (i = 0; i < ARRAY_SIZE(acpi_battery_blacklist); i++) - if (acpi_dev_present(acpi_battery_blacklist[i], "1", -1)) { - pr_info(PREFIX ACPI_BATTERY_DEVICE_NAME - ": found native %s PMIC, not loading\n", - acpi_battery_blacklist[i]); - return; - } - dmi_check_system(bat_dmi_table); + if (battery_check_pmic) { + for (i = 0; i < ARRAY_SIZE(acpi_battery_blacklist); i++) + if (acpi_dev_present(acpi_battery_blacklist[i], "1", -1)) { + pr_info(PREFIX ACPI_BATTERY_DEVICE_NAME + ": found native %s PMIC, not loading\n", + acpi_battery_blacklist[i]); + return; + } + } + #ifdef CONFIG_ACPI_PROCFS_POWER acpi_battery_dir = acpi_lock_battery_dir(); if (!acpi_battery_dir) diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index f1cc4f9d31cd..2345a5ee2dbb 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -263,19 +263,6 @@ static int acpi_button_state_seq_show(struct seq_file *seq, void *offset) return 0; } -static int acpi_button_state_open_fs(struct inode *inode, struct file *file) -{ - return single_open(file, acpi_button_state_seq_show, PDE_DATA(inode)); -} - -static const struct file_operations acpi_button_state_fops = { - .owner = THIS_MODULE, - .open = acpi_button_state_open_fs, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static int acpi_button_add_fs(struct acpi_device *device) { struct acpi_button *button = acpi_driver_data(device); @@ -311,9 +298,9 @@ static int acpi_button_add_fs(struct acpi_device *device) } /* create /proc/acpi/button/lid/LID/state */ - entry = proc_create_data(ACPI_BUTTON_FILE_STATE, - S_IRUGO, acpi_device_dir(device), - &acpi_button_state_fops, device); + entry = proc_create_single_data(ACPI_BUTTON_FILE_STATE, S_IRUGO, + acpi_device_dir(device), acpi_button_state_seq_show, + device); if (!entry) { ret = -ENODEV; goto remove_dev_dir; diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index 735c74a4cbdb..d9ce4b162e2c 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c @@ -39,6 +39,7 @@ #include <linux/cpufreq.h> #include <linux/delay.h> +#include <linux/iopoll.h> #include <linux/ktime.h> #include <linux/rwsem.h> #include <linux/wait.h> @@ -49,7 +50,7 @@ struct cppc_pcc_data { struct mbox_chan *pcc_channel; void __iomem *pcc_comm_addr; bool pcc_channel_acquired; - ktime_t deadline; + unsigned int deadline_us; unsigned int pcc_mpar, pcc_mrtt, pcc_nominal; bool pending_pcc_write_cmd; /* Any pending/batched PCC write cmds? */ @@ -156,6 +157,9 @@ show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, highest_perf); show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, lowest_perf); show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, nominal_perf); show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, lowest_nonlinear_perf); +show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, lowest_freq); +show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, nominal_freq); + show_cppc_data(cppc_get_perf_ctrs, cppc_perf_fb_ctrs, reference_perf); show_cppc_data(cppc_get_perf_ctrs, cppc_perf_fb_ctrs, wraparound_time); @@ -183,6 +187,8 @@ static struct attribute *cppc_attrs[] = { &lowest_perf.attr, &lowest_nonlinear_perf.attr, &nominal_perf.attr, + &nominal_freq.attr, + &lowest_freq.attr, NULL }; @@ -193,42 +199,31 @@ static struct kobj_type cppc_ktype = { static int check_pcc_chan(int pcc_ss_id, bool chk_err_bit) { - int ret = -EIO, status = 0; + int ret, status; struct cppc_pcc_data *pcc_ss_data = pcc_data[pcc_ss_id]; struct acpi_pcct_shared_memory __iomem *generic_comm_base = pcc_ss_data->pcc_comm_addr; - ktime_t next_deadline = ktime_add(ktime_get(), - pcc_ss_data->deadline); if (!pcc_ss_data->platform_owns_pcc) return 0; - /* Retry in case the remote processor was too slow to catch up. */ - while (!ktime_after(ktime_get(), next_deadline)) { - /* - * Per spec, prior to boot the PCC space wil be initialized by - * platform and should have set the command completion bit when - * PCC can be used by OSPM - */ - status = readw_relaxed(&generic_comm_base->status); - if (status & PCC_CMD_COMPLETE_MASK) { - ret = 0; - if (chk_err_bit && (status & PCC_ERROR_MASK)) - ret = -EIO; - break; - } - /* - * Reducing the bus traffic in case this loop takes longer than - * a few retries. - */ - udelay(3); - } + /* + * Poll PCC status register every 3us(delay_us) for maximum of + * deadline_us(timeout_us) until PCC command complete bit is set(cond) + */ + ret = readw_relaxed_poll_timeout(&generic_comm_base->status, status, + status & PCC_CMD_COMPLETE_MASK, 3, + pcc_ss_data->deadline_us); - if (likely(!ret)) + if (likely(!ret)) { pcc_ss_data->platform_owns_pcc = false; - else - pr_err("PCC check channel failed for ss: %d. Status=%x\n", - pcc_ss_id, status); + if (chk_err_bit && (status & PCC_ERROR_MASK)) + ret = -EIO; + } + + if (unlikely(ret)) + pr_err("PCC check channel failed for ss: %d. ret=%d\n", + pcc_ss_id, ret); return ret; } @@ -580,7 +575,7 @@ static int register_pcc_channel(int pcc_ss_idx) * So add an arbitrary amount of wait on top of Nominal. */ usecs_lat = NUM_RETRIES * cppc_ss->latency; - pcc_data[pcc_ss_idx]->deadline = ns_to_ktime(usecs_lat * NSEC_PER_USEC); + pcc_data[pcc_ss_idx]->deadline_us = usecs_lat; pcc_data[pcc_ss_idx]->pcc_mrtt = cppc_ss->min_turnaround_time; pcc_data[pcc_ss_idx]->pcc_mpar = cppc_ss->max_access_rate; pcc_data[pcc_ss_idx]->pcc_nominal = cppc_ss->latency; @@ -613,7 +608,6 @@ bool __weak cpc_ffh_supported(void) return false; } - /** * pcc_data_alloc() - Allocate the pcc_data memory for pcc subspace * @@ -641,6 +635,34 @@ int pcc_data_alloc(int pcc_ss_id) return 0; } + +/* Check if CPPC revision + num_ent combination is supported */ +static bool is_cppc_supported(int revision, int num_ent) +{ + int expected_num_ent; + + switch (revision) { + case CPPC_V2_REV: + expected_num_ent = CPPC_V2_NUM_ENT; + break; + case CPPC_V3_REV: + expected_num_ent = CPPC_V3_NUM_ENT; + break; + default: + pr_debug("Firmware exports unsupported CPPC revision: %d\n", + revision); + return false; + } + + if (expected_num_ent != num_ent) { + pr_debug("Firmware exports %d entries. Expected: %d for CPPC rev:%d\n", + num_ent, expected_num_ent, revision); + return false; + } + + return true; +} + /* * An example CPC table looks like the following. * @@ -731,14 +753,6 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr) cpc_obj->type); goto out_free; } - - /* Only support CPPCv2. Bail otherwise. */ - if (num_ent != CPPC_NUM_ENT) { - pr_debug("Firmware exports %d entries. Expected: %d\n", - num_ent, CPPC_NUM_ENT); - goto out_free; - } - cpc_ptr->num_entries = num_ent; /* Second entry should be revision. */ @@ -750,12 +764,10 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr) cpc_obj->type); goto out_free; } + cpc_ptr->version = cpc_rev; - if (cpc_rev != CPPC_REV) { - pr_debug("Firmware exports revision:%d. Expected:%d\n", - cpc_rev, CPPC_REV); + if (!is_cppc_supported(cpc_rev, num_ent)) goto out_free; - } /* Iterate through remaining entries in _CPC */ for (i = 2; i < num_ent; i++) { @@ -808,6 +820,18 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr) } } per_cpu(cpu_pcc_subspace_idx, pr->id) = pcc_subspace_id; + + /* + * Initialize the remaining cpc_regs as unsupported. + * Example: In case FW exposes CPPC v2, the below loop will initialize + * LOWEST_FREQ and NOMINAL_FREQ regs as unsupported + */ + for (i = num_ent - 2; i < MAX_CPC_REG_ENT; i++) { + cpc_ptr->cpc_regs[i].type = ACPI_TYPE_INTEGER; + cpc_ptr->cpc_regs[i].cpc_entry.int_value = 0; + } + + /* Store CPU Logical ID */ cpc_ptr->cpu_id = pr->id; @@ -1037,26 +1061,34 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps) { struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpunum); struct cpc_register_resource *highest_reg, *lowest_reg, - *lowest_non_linear_reg, *nominal_reg; - u64 high, low, nom, min_nonlinear; + *lowest_non_linear_reg, *nominal_reg, + *low_freq_reg = NULL, *nom_freq_reg = NULL; + u64 high, low, nom, min_nonlinear, low_f = 0, nom_f = 0; int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpunum); - struct cppc_pcc_data *pcc_ss_data; + struct cppc_pcc_data *pcc_ss_data = NULL; int ret = 0, regs_in_pcc = 0; - if (!cpc_desc || pcc_ss_id < 0) { + if (!cpc_desc) { pr_debug("No CPC descriptor for CPU:%d\n", cpunum); return -ENODEV; } - pcc_ss_data = pcc_data[pcc_ss_id]; highest_reg = &cpc_desc->cpc_regs[HIGHEST_PERF]; lowest_reg = &cpc_desc->cpc_regs[LOWEST_PERF]; lowest_non_linear_reg = &cpc_desc->cpc_regs[LOW_NON_LINEAR_PERF]; nominal_reg = &cpc_desc->cpc_regs[NOMINAL_PERF]; + low_freq_reg = &cpc_desc->cpc_regs[LOWEST_FREQ]; + nom_freq_reg = &cpc_desc->cpc_regs[NOMINAL_FREQ]; /* Are any of the regs PCC ?*/ if (CPC_IN_PCC(highest_reg) || CPC_IN_PCC(lowest_reg) || - CPC_IN_PCC(lowest_non_linear_reg) || CPC_IN_PCC(nominal_reg)) { + CPC_IN_PCC(lowest_non_linear_reg) || CPC_IN_PCC(nominal_reg) || + CPC_IN_PCC(low_freq_reg) || CPC_IN_PCC(nom_freq_reg)) { + if (pcc_ss_id < 0) { + pr_debug("Invalid pcc_ss_id\n"); + return -ENODEV; + } + pcc_ss_data = pcc_data[pcc_ss_id]; regs_in_pcc = 1; down_write(&pcc_ss_data->pcc_lock); /* Ring doorbell once to update PCC subspace */ @@ -1081,6 +1113,17 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps) if (!high || !low || !nom || !min_nonlinear) ret = -EFAULT; + /* Read optional lowest and nominal frequencies if present */ + if (CPC_SUPPORTED(low_freq_reg)) + cpc_read(cpunum, low_freq_reg, &low_f); + + if (CPC_SUPPORTED(nom_freq_reg)) + cpc_read(cpunum, nom_freq_reg, &nom_f); + + perf_caps->lowest_freq = low_f; + perf_caps->nominal_freq = nom_f; + + out_err: if (regs_in_pcc) up_write(&pcc_ss_data->pcc_lock); @@ -1101,16 +1144,15 @@ int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs) struct cpc_register_resource *delivered_reg, *reference_reg, *ref_perf_reg, *ctr_wrap_reg; int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpunum); - struct cppc_pcc_data *pcc_ss_data; + struct cppc_pcc_data *pcc_ss_data = NULL; u64 delivered, reference, ref_perf, ctr_wrap_time; int ret = 0, regs_in_pcc = 0; - if (!cpc_desc || pcc_ss_id < 0) { + if (!cpc_desc) { pr_debug("No CPC descriptor for CPU:%d\n", cpunum); return -ENODEV; } - pcc_ss_data = pcc_data[pcc_ss_id]; delivered_reg = &cpc_desc->cpc_regs[DELIVERED_CTR]; reference_reg = &cpc_desc->cpc_regs[REFERENCE_CTR]; ref_perf_reg = &cpc_desc->cpc_regs[REFERENCE_PERF]; @@ -1126,6 +1168,11 @@ int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs) /* Are any of the regs PCC ?*/ if (CPC_IN_PCC(delivered_reg) || CPC_IN_PCC(reference_reg) || CPC_IN_PCC(ctr_wrap_reg) || CPC_IN_PCC(ref_perf_reg)) { + if (pcc_ss_id < 0) { + pr_debug("Invalid pcc_ss_id\n"); + return -ENODEV; + } + pcc_ss_data = pcc_data[pcc_ss_id]; down_write(&pcc_ss_data->pcc_lock); regs_in_pcc = 1; /* Ring doorbell once to update PCC subspace */ @@ -1176,15 +1223,14 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls) struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu); struct cpc_register_resource *desired_reg; int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu); - struct cppc_pcc_data *pcc_ss_data; + struct cppc_pcc_data *pcc_ss_data = NULL; int ret = 0; - if (!cpc_desc || pcc_ss_id < 0) { + if (!cpc_desc) { pr_debug("No CPC descriptor for CPU:%d\n", cpu); return -ENODEV; } - pcc_ss_data = pcc_data[pcc_ss_id]; desired_reg = &cpc_desc->cpc_regs[DESIRED_PERF]; /* @@ -1195,6 +1241,11 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls) * achieve that goal here */ if (CPC_IN_PCC(desired_reg)) { + if (pcc_ss_id < 0) { + pr_debug("Invalid pcc_ss_id\n"); + return -ENODEV; + } + pcc_ss_data = pcc_data[pcc_ss_id]; down_read(&pcc_ss_data->pcc_lock); /* BEGIN Phase-I */ if (pcc_ss_data->platform_owns_pcc) { ret = check_pcc_chan(pcc_ss_id, false); diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 3d96e4da2d98..a7c2673ffd36 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -1257,10 +1257,7 @@ int acpi_dev_pm_attach(struct device *dev, bool power_on) struct acpi_device *adev = ACPI_COMPANION(dev); if (!adev) - return -ENODEV; - - if (dev->pm_domain) - return -EEXIST; + return 0; /* * Only attach the power domain to the first device if the @@ -1268,7 +1265,7 @@ int acpi_dev_pm_attach(struct device *dev, bool power_on) * management twice. */ if (!acpi_device_is_first_physical_node(adev, dev)) - return -EBUSY; + return 0; acpi_add_pm_notifier(adev, dev, acpi_pm_notify_work_func); dev_pm_domain_set(dev, &acpi_general_pm_domain); @@ -1278,7 +1275,7 @@ int acpi_dev_pm_attach(struct device *dev, bool power_on) } dev->pm_domain->detach = acpi_dev_pm_detach; - return 0; + return 1; } EXPORT_SYMBOL_GPL(acpi_dev_pm_attach); #endif /* CONFIG_PM */ diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 30a572956557..bb94cf0731fe 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -1034,6 +1034,12 @@ void acpi_ec_unblock_transactions(void) acpi_ec_start(first_ec, true); } +void acpi_ec_dispatch_gpe(void) +{ + if (first_ec) + acpi_dispatch_gpe(NULL, first_ec->gpe); +} + /* -------------------------------------------------------------------------- Event Management -------------------------------------------------------------------------- */ diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 1d0a501bc7f0..530a3f675490 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -188,6 +188,7 @@ int acpi_ec_ecdt_probe(void); int acpi_ec_dsdt_probe(void); void acpi_ec_block_transactions(void); void acpi_ec_unblock_transactions(void); +void acpi_ec_dispatch_gpe(void); int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, acpi_handle handle, acpi_ec_query_func func, void *data); diff --git a/drivers/acpi/reboot.c b/drivers/acpi/reboot.c index 71769fd687b2..6fa9c2a4cfe9 100644 --- a/drivers/acpi/reboot.c +++ b/drivers/acpi/reboot.c @@ -8,8 +8,8 @@ void acpi_reboot(void) { struct acpi_generic_address *rr; struct pci_bus *bus0; - u8 reset_value; unsigned int devfn; + u8 reset_value; if (acpi_disabled) return; @@ -40,7 +40,7 @@ void acpi_reboot(void) /* Form PCI device/function pair. */ devfn = PCI_DEVFN((rr->address >> 32) & 0xffff, (rr->address >> 16) & 0xffff); - printk(KERN_DEBUG "Resetting with ACPI PCI RESET_REG."); + printk(KERN_DEBUG "Resetting with ACPI PCI RESET_REG.\n"); /* Write the value that resets us. */ pci_bus_write_config_byte(bus0, devfn, (rr->address & 0xffff), reset_value); diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 974e58457697..5d0486f1cfcd 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -989,6 +989,13 @@ static void acpi_s2idle_wake(void) !irqd_is_wakeup_armed(irq_get_irq_data(acpi_sci_irq))) { pm_system_cancel_wakeup(); s2idle_wakeup = true; + /* + * On some platforms with the LPS0 _DSM device noirq resume + * takes too much time for EC wakeup events to survive, so look + * for them now. + */ + if (lps0_device_handle) + acpi_ec_dispatch_gpe(); } } diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index 849c4fb19b03..4a3410aa6540 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -222,7 +222,7 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header) * acpi_parse_entries_array - for each proc_num find a suitable subtable * * @id: table id (for debugging purposes) - * @table_size: single entry size + * @table_size: size of the root table * @table_header: where does the table start? * @proc: array of acpi_subtable_proc struct containing entry id * and associated handler with it @@ -233,6 +233,11 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header) * on it. Assumption is that there's only single handler for particular * entry id. * + * The table_size is not the size of the complete ACPI table (the length + * field in the header struct), but only the size of the root table; i.e., + * the offset from the very first byte of the complete ACPI table, to the + * first byte of the very first subtable. + * * On success returns sum of all matching entries for all proc handlers. * Otherwise, -ENODEV or -EINVAL is returned. */ @@ -400,7 +405,7 @@ int __init acpi_table_parse(char *id, acpi_tbl_table_handler handler) return -ENODEV; } -/* +/* * The BIOS is supposed to supply a single APIC/MADT, * but some report two. Provide a knob to use either. * (don't you wish instance 0 and 1 were not the same?) diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index 4a3ac31c07d0..0cf51d57e4ae 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -20,6 +20,7 @@ #include <linux/sizes.h> #include <linux/limits.h> #include <linux/clk/clk-conf.h> +#include <linux/platform_device.h> #include <asm/irq.h> @@ -193,14 +194,16 @@ static const struct dev_pm_ops amba_pm = { /* * Primecells are part of the Advanced Microcontroller Bus Architecture, * so we call the bus "amba". + * DMA configuration for platform and AMBA bus is same. So here we reuse + * platform's DMA config routine. */ struct bus_type amba_bustype = { .name = "amba", .dev_groups = amba_dev_groups, .match = amba_match, .uevent = amba_uevent, + .dma_configure = platform_dma_configure, .pm = &amba_pm, - .force_dma = true, }; static int __init amba_init(void) @@ -248,7 +251,7 @@ static int amba_probe(struct device *dev) break; ret = dev_pm_domain_attach(dev, true); - if (ret == -EPROBE_DEFER) + if (ret) break; ret = amba_get_enable_pclk(pcdev); @@ -375,7 +378,7 @@ static int amba_device_try_add(struct amba_device *dev, struct resource *parent) } ret = dev_pm_domain_attach(&dev->dev, true); - if (ret == -EPROBE_DEFER) { + if (ret) { iounmap(tmp); goto err_release; } diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 6389c88b3500..738fb22978dd 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -334,6 +334,7 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x9c07), board_ahci_mobile }, /* Lynx LP RAID */ { PCI_VDEVICE(INTEL, 0x9c0e), board_ahci_mobile }, /* Lynx LP RAID */ { PCI_VDEVICE(INTEL, 0x9c0f), board_ahci_mobile }, /* Lynx LP RAID */ + { PCI_VDEVICE(INTEL, 0x9dd3), board_ahci_mobile }, /* Cannon Lake PCH-LP AHCI */ { PCI_VDEVICE(INTEL, 0x1f22), board_ahci }, /* Avoton AHCI */ { PCI_VDEVICE(INTEL, 0x1f23), board_ahci }, /* Avoton AHCI */ { PCI_VDEVICE(INTEL, 0x1f24), board_ahci }, /* Avoton RAID */ diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 68596bd4cf06..346b163f6e89 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4493,6 +4493,10 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { /* https://bugzilla.kernel.org/show_bug.cgi?id=15573 */ { "C300-CTFDDAC128MAG", "0001", ATA_HORKAGE_NONCQ, }, + /* Some Sandisk SSDs lock up hard with NCQ enabled. Reported on + SD7SN6S256G and SD8SN8U256G */ + { "SanDisk SD[78]SN*G", NULL, ATA_HORKAGE_NONCQ, }, + /* devices which puke on READ_NATIVE_MAX */ { "HDS724040KLSA80", "KFAOA20N", ATA_HORKAGE_BROKEN_HPA, }, { "WDC WD3200JD-00KLB0", "WD-WCAMR1130137", ATA_HORKAGE_BROKEN_HPA }, @@ -4549,13 +4553,16 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { ATA_HORKAGE_ZERO_AFTER_TRIM | ATA_HORKAGE_NOLPM, }, - /* This specific Samsung model/firmware-rev does not handle LPM well */ + /* These specific Samsung models/firmware-revs do not handle LPM well */ { "SAMSUNG MZMPC128HBFU-000MV", "CXM14M1Q", ATA_HORKAGE_NOLPM, }, + { "SAMSUNG SSD PM830 mSATA *", "CXM13D1Q", ATA_HORKAGE_NOLPM, }, /* Sandisk devices which are known to not handle LPM well */ { "SanDisk SD7UB3Q*G1001", NULL, ATA_HORKAGE_NOLPM, }, /* devices that don't properly handle queued TRIM commands */ + { "Micron_M500IT_*", "MU01", ATA_HORKAGE_NO_NCQ_TRIM | + ATA_HORKAGE_ZERO_AFTER_TRIM, }, { "Micron_M500_*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | ATA_HORKAGE_ZERO_AFTER_TRIM, }, { "Crucial_CT*M500*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 513b260bcff1..a2398e28c295 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -500,57 +500,6 @@ void ata_eh_release(struct ata_port *ap) mutex_unlock(&ap->host->eh_mutex); } -/** - * ata_scsi_timed_out - SCSI layer time out callback - * @cmd: timed out SCSI command - * - * Handles SCSI layer timeout. We race with normal completion of - * the qc for @cmd. If the qc is already gone, we lose and let - * the scsi command finish (EH_HANDLED). Otherwise, the qc has - * timed out and EH should be invoked. Prevent ata_qc_complete() - * from finishing it by setting EH_SCHEDULED and return - * EH_NOT_HANDLED. - * - * TODO: kill this function once old EH is gone. - * - * LOCKING: - * Called from timer context - * - * RETURNS: - * EH_HANDLED or EH_NOT_HANDLED - */ -enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd) -{ - struct Scsi_Host *host = cmd->device->host; - struct ata_port *ap = ata_shost_to_port(host); - unsigned long flags; - struct ata_queued_cmd *qc; - enum blk_eh_timer_return ret; - - DPRINTK("ENTER\n"); - - if (ap->ops->error_handler) { - ret = BLK_EH_NOT_HANDLED; - goto out; - } - - ret = BLK_EH_HANDLED; - spin_lock_irqsave(ap->lock, flags); - qc = ata_qc_from_tag(ap, ap->link.active_tag); - if (qc) { - WARN_ON(qc->scsicmd != cmd); - qc->flags |= ATA_QCFLAG_EH_SCHEDULED; - qc->err_mask |= AC_ERR_TIMEOUT; - ret = BLK_EH_NOT_HANDLED; - } - spin_unlock_irqrestore(ap->lock, flags); - - out: - DPRINTK("EXIT, ret=%d\n", ret); - return ret; -} -EXPORT_SYMBOL(ata_scsi_timed_out); - static void ata_eh_unload(struct ata_port *ap) { struct ata_link *link; diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c index 9c9a22958717..a8d2eb0ceb8d 100644 --- a/drivers/atm/zatm.c +++ b/drivers/atm/zatm.c @@ -1151,8 +1151,8 @@ static void eprom_get_byte(struct zatm_dev *zatm_dev, unsigned char *byte, } -static unsigned char eprom_try_esi(struct atm_dev *dev, unsigned short cmd, - int offset, int swap) +static int eprom_try_esi(struct atm_dev *dev, unsigned short cmd, int offset, + int swap) { unsigned char buf[ZEPROM_SIZE]; struct zatm_dev *zatm_dev; diff --git a/drivers/base/base.h b/drivers/base/base.h index d800de650fa5..a75c3025fb78 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -161,3 +161,6 @@ extern void device_links_driver_cleanup(struct device *dev); extern void device_links_no_driver(struct device *dev); extern bool device_links_busy(struct device *dev); extern void device_links_unbind_consumers(struct device *dev); + +/* device pm support */ +void device_pm_move_to_tail(struct device *dev); diff --git a/drivers/base/core.c b/drivers/base/core.c index b610816eb887..ad7b50897bcc 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -145,6 +145,26 @@ static int device_reorder_to_tail(struct device *dev, void *not_used) } /** + * device_pm_move_to_tail - Move set of devices to the end of device lists + * @dev: Device to move + * + * This is a device_reorder_to_tail() wrapper taking the requisite locks. + * + * It moves the @dev along with all of its children and all of its consumers + * to the ends of the device_kset and dpm_list, recursively. + */ +void device_pm_move_to_tail(struct device *dev) +{ + int idx; + + idx = device_links_read_lock(); + device_pm_lock(); + device_reorder_to_tail(dev, NULL); + device_pm_unlock(); + device_links_read_unlock(idx); +} + +/** * device_link_add - Create a link between two devices. * @consumer: Consumer end of the link. * @supplier: Supplier end of the link. diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 2da998baa75c..30cc9c877ebb 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -534,14 +534,22 @@ ssize_t __weak cpu_show_spectre_v2(struct device *dev, return sprintf(buf, "Not affected\n"); } +ssize_t __weak cpu_show_spec_store_bypass(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "Not affected\n"); +} + static DEVICE_ATTR(meltdown, 0444, cpu_show_meltdown, NULL); static DEVICE_ATTR(spectre_v1, 0444, cpu_show_spectre_v1, NULL); static DEVICE_ATTR(spectre_v2, 0444, cpu_show_spectre_v2, NULL); +static DEVICE_ATTR(spec_store_bypass, 0444, cpu_show_spec_store_bypass, NULL); static struct attribute *cpu_root_vulnerabilities_attrs[] = { &dev_attr_meltdown.attr, &dev_attr_spectre_v1.attr, &dev_attr_spectre_v2.attr, + &dev_attr_spec_store_bypass.attr, NULL }; diff --git a/drivers/base/dd.c b/drivers/base/dd.c index c9f54089429b..a41c91bfac0e 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -122,9 +122,7 @@ static void deferred_probe_work_func(struct work_struct *work) * the list is a good order for suspend but deferred * probe makes that very unsafe. */ - device_pm_lock(); - device_pm_move_last(dev); - device_pm_unlock(); + device_pm_move_to_tail(dev); dev_dbg(dev, "Retrying from deferred list\n"); if (initcall_debug && !initcalls_done) @@ -582,7 +580,7 @@ int driver_probe_device(struct device_driver *drv, struct device *dev) pr_debug("bus: '%s': %s: matched device %s with driver %s\n", drv->bus->name, __func__, dev_name(dev), drv->name); - pm_runtime_get_suppliers(dev); + pm_runtime_resume_suppliers(dev); if (dev->parent) pm_runtime_get_sync(dev->parent); @@ -593,7 +591,6 @@ int driver_probe_device(struct device_driver *drv, struct device *dev) if (dev->parent) pm_runtime_put(dev->parent); - pm_runtime_put_suppliers(dev); return ret; } diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c index d82566d6e237..f831a582209c 100644 --- a/drivers/base/dma-mapping.c +++ b/drivers/base/dma-mapping.c @@ -329,36 +329,13 @@ void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags) #endif /* - * Common configuration to enable DMA API use for a device + * enables DMA API use for a device */ -#include <linux/pci.h> - int dma_configure(struct device *dev) { - struct device *bridge = NULL, *dma_dev = dev; - enum dev_dma_attr attr; - int ret = 0; - - if (dev_is_pci(dev)) { - bridge = pci_get_host_bridge_device(to_pci_dev(dev)); - dma_dev = bridge; - if (IS_ENABLED(CONFIG_OF) && dma_dev->parent && - dma_dev->parent->of_node) - dma_dev = dma_dev->parent; - } - - if (dma_dev->of_node) { - ret = of_dma_configure(dev, dma_dev->of_node); - } else if (has_acpi_companion(dma_dev)) { - attr = acpi_get_dma_attr(to_acpi_device_node(dma_dev->fwnode)); - if (attr != DEV_DMA_NOT_SUPPORTED) - ret = acpi_dma_configure(dev, attr); - } - - if (bridge) - pci_put_host_bridge_device(bridge); - - return ret; + if (dev->bus->dma_configure) + return dev->bus->dma_configure(dev); + return 0; } void dma_deconfigure(struct device *dev) diff --git a/drivers/base/node.c b/drivers/base/node.c index 7a3a580821e0..a5e821d09656 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -490,7 +490,8 @@ int unregister_mem_sect_under_nodes(struct memory_block *mem_blk, return 0; } -int link_mem_sections(int nid, unsigned long start_pfn, unsigned long nr_pages) +int link_mem_sections(int nid, unsigned long start_pfn, unsigned long nr_pages, + bool check_nid) { unsigned long end_pfn = start_pfn + nr_pages; unsigned long pfn; @@ -514,7 +515,7 @@ int link_mem_sections(int nid, unsigned long start_pfn, unsigned long nr_pages) mem_blk = find_memory_block_hinted(mem_sect, mem_blk); - ret = register_mem_sect_under_node(mem_blk, nid, true); + ret = register_mem_sect_under_node(mem_blk, nid, check_nid); if (!err) err = ret; diff --git a/drivers/base/platform-msi.c b/drivers/base/platform-msi.c index 8e22073aeeed..60d6cc618f1c 100644 --- a/drivers/base/platform-msi.c +++ b/drivers/base/platform-msi.c @@ -101,6 +101,9 @@ static void platform_msi_update_chip_ops(struct msi_domain_info *info) chip->irq_set_affinity = msi_domain_set_affinity; if (!chip->irq_write_msi_msg) chip->irq_write_msi_msg = platform_msi_write_msg; + if (WARN_ON((info->flags & MSI_FLAG_LEVEL_CAPABLE) && + !(chip->flags & IRQCHIP_SUPPORTS_LEVEL_MSI))) + info->flags &= ~MSI_FLAG_LEVEL_CAPABLE; } static void platform_msi_free_descs(struct device *dev, int base, int nvec) diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 8075ddc70a17..dff82a3c2caa 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -572,17 +572,16 @@ static int platform_drv_probe(struct device *_dev) return ret; ret = dev_pm_domain_attach(_dev, true); - if (ret != -EPROBE_DEFER) { - if (drv->probe) { - ret = drv->probe(dev); - if (ret) - dev_pm_domain_detach(_dev, true); - } else { - /* don't fail if just dev_pm_domain_attach failed */ - ret = 0; - } + if (ret) + goto out; + + if (drv->probe) { + ret = drv->probe(dev); + if (ret) + dev_pm_domain_detach(_dev, true); } +out: if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) { dev_warn(_dev, "probe deferral not supported\n"); ret = -ENXIO; @@ -1130,6 +1129,22 @@ int platform_pm_restore(struct device *dev) #endif /* CONFIG_HIBERNATE_CALLBACKS */ +int platform_dma_configure(struct device *dev) +{ + enum dev_dma_attr attr; + int ret = 0; + + if (dev->of_node) { + ret = of_dma_configure(dev, dev->of_node, true); + } else if (has_acpi_companion(dev)) { + attr = acpi_get_dma_attr(to_acpi_device_node(dev->fwnode)); + if (attr != DEV_DMA_NOT_SUPPORTED) + ret = acpi_dma_configure(dev, attr); + } + + return ret; +} + static const struct dev_pm_ops platform_dev_pm_ops = { .runtime_suspend = pm_generic_runtime_suspend, .runtime_resume = pm_generic_runtime_resume, @@ -1141,8 +1156,8 @@ struct bus_type platform_bus_type = { .dev_groups = platform_dev_groups, .match = platform_match, .uevent = platform_uevent, + .dma_configure = platform_dma_configure, .pm = &platform_dev_pm_ops, - .force_dma = true, }; EXPORT_SYMBOL_GPL(platform_bus_type); diff --git a/drivers/base/power/common.c b/drivers/base/power/common.c index f6a9ad52cbbf..7ae62b6355b8 100644 --- a/drivers/base/power/common.c +++ b/drivers/base/power/common.c @@ -98,17 +98,21 @@ EXPORT_SYMBOL_GPL(dev_pm_put_subsys_data); * Callers must ensure proper synchronization of this function with power * management callbacks. * - * Returns 0 on successfully attached PM domain or negative error code. + * Returns 0 on successfully attached PM domain, or when it is found that the + * device doesn't need a PM domain, else a negative error code. */ int dev_pm_domain_attach(struct device *dev, bool power_on) { int ret; + if (dev->pm_domain) + return 0; + ret = acpi_dev_pm_attach(dev, power_on); - if (ret) + if (!ret) ret = genpd_dev_pm_attach(dev); - return ret; + return ret < 0 ? ret : 0; } EXPORT_SYMBOL_GPL(dev_pm_domain_attach); diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 1ea0e2502e8e..6f403d6fccb2 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -10,6 +10,7 @@ #include <linux/kernel.h> #include <linux/io.h> #include <linux/platform_device.h> +#include <linux/pm_opp.h> #include <linux/pm_runtime.h> #include <linux/pm_domain.h> #include <linux/pm_qos.h> @@ -1315,7 +1316,6 @@ EXPORT_SYMBOL_GPL(pm_genpd_syscore_poweron); #endif /* CONFIG_PM_SLEEP */ static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev, - struct generic_pm_domain *genpd, struct gpd_timing_data *td) { struct generic_pm_domain_data *gpd_data; @@ -1377,24 +1377,19 @@ static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, struct gpd_timing_data *td) { struct generic_pm_domain_data *gpd_data; - int ret = 0; + int ret; dev_dbg(dev, "%s()\n", __func__); if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev)) return -EINVAL; - gpd_data = genpd_alloc_dev_data(dev, genpd, td); + gpd_data = genpd_alloc_dev_data(dev, td); if (IS_ERR(gpd_data)) return PTR_ERR(gpd_data); genpd_lock(genpd); - if (genpd->prepared_count > 0) { - ret = -EAGAIN; - goto out; - } - ret = genpd->attach_dev ? genpd->attach_dev(genpd, dev) : 0; if (ret) goto out; @@ -1418,23 +1413,21 @@ static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, } /** - * __pm_genpd_add_device - Add a device to an I/O PM domain. + * pm_genpd_add_device - Add a device to an I/O PM domain. * @genpd: PM domain to add the device to. * @dev: Device to be added. - * @td: Set of PM QoS timing parameters to attach to the device. */ -int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, - struct gpd_timing_data *td) +int pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev) { int ret; mutex_lock(&gpd_list_lock); - ret = genpd_add_device(genpd, dev, td); + ret = genpd_add_device(genpd, dev, NULL); mutex_unlock(&gpd_list_lock); return ret; } -EXPORT_SYMBOL_GPL(__pm_genpd_add_device); +EXPORT_SYMBOL_GPL(pm_genpd_add_device); static int genpd_remove_device(struct generic_pm_domain *genpd, struct device *dev) @@ -1481,13 +1474,13 @@ static int genpd_remove_device(struct generic_pm_domain *genpd, /** * pm_genpd_remove_device - Remove a device from an I/O PM domain. - * @genpd: PM domain to remove the device from. * @dev: Device to be removed. */ -int pm_genpd_remove_device(struct generic_pm_domain *genpd, - struct device *dev) +int pm_genpd_remove_device(struct device *dev) { - if (!genpd || genpd != genpd_lookup_dev(dev)) + struct generic_pm_domain *genpd = genpd_lookup_dev(dev); + + if (!genpd) return -EINVAL; return genpd_remove_device(genpd, dev); @@ -1696,6 +1689,9 @@ int pm_genpd_init(struct generic_pm_domain *genpd, return ret; } + device_initialize(&genpd->dev); + dev_set_name(&genpd->dev, "%s", genpd->name); + mutex_lock(&gpd_list_lock); list_add(&genpd->gpd_list_node, &gpd_list); mutex_unlock(&gpd_list_lock); @@ -1892,14 +1888,33 @@ int of_genpd_add_provider_simple(struct device_node *np, mutex_lock(&gpd_list_lock); - if (genpd_present(genpd)) { - ret = genpd_add_provider(np, genpd_xlate_simple, genpd); - if (!ret) { - genpd->provider = &np->fwnode; - genpd->has_provider = true; + if (!genpd_present(genpd)) + goto unlock; + + genpd->dev.of_node = np; + + /* Parse genpd OPP table */ + if (genpd->set_performance_state) { + ret = dev_pm_opp_of_add_table(&genpd->dev); + if (ret) { + dev_err(&genpd->dev, "Failed to add OPP table: %d\n", + ret); + goto unlock; } } + ret = genpd_add_provider(np, genpd_xlate_simple, genpd); + if (ret) { + if (genpd->set_performance_state) + dev_pm_opp_of_remove_table(&genpd->dev); + + goto unlock; + } + + genpd->provider = &np->fwnode; + genpd->has_provider = true; + +unlock: mutex_unlock(&gpd_list_lock); return ret; @@ -1914,6 +1929,7 @@ EXPORT_SYMBOL_GPL(of_genpd_add_provider_simple); int of_genpd_add_provider_onecell(struct device_node *np, struct genpd_onecell_data *data) { + struct generic_pm_domain *genpd; unsigned int i; int ret = -EINVAL; @@ -1926,13 +1942,27 @@ int of_genpd_add_provider_onecell(struct device_node *np, data->xlate = genpd_xlate_onecell; for (i = 0; i < data->num_domains; i++) { - if (!data->domains[i]) + genpd = data->domains[i]; + + if (!genpd) continue; - if (!genpd_present(data->domains[i])) + if (!genpd_present(genpd)) goto error; - data->domains[i]->provider = &np->fwnode; - data->domains[i]->has_provider = true; + genpd->dev.of_node = np; + + /* Parse genpd OPP table */ + if (genpd->set_performance_state) { + ret = dev_pm_opp_of_add_table_indexed(&genpd->dev, i); + if (ret) { + dev_err(&genpd->dev, "Failed to add OPP table for index %d: %d\n", + i, ret); + goto error; + } + } + + genpd->provider = &np->fwnode; + genpd->has_provider = true; } ret = genpd_add_provider(np, data->xlate, data); @@ -1945,10 +1975,16 @@ int of_genpd_add_provider_onecell(struct device_node *np, error: while (i--) { - if (!data->domains[i]) + genpd = data->domains[i]; + + if (!genpd) continue; - data->domains[i]->provider = NULL; - data->domains[i]->has_provider = false; + + genpd->provider = NULL; + genpd->has_provider = false; + + if (genpd->set_performance_state) + dev_pm_opp_of_remove_table(&genpd->dev); } mutex_unlock(&gpd_list_lock); @@ -1975,10 +2011,17 @@ void of_genpd_del_provider(struct device_node *np) * provider, set the 'has_provider' to false * so that the PM domain can be safely removed. */ - list_for_each_entry(gpd, &gpd_list, gpd_list_node) - if (gpd->provider == &np->fwnode) + list_for_each_entry(gpd, &gpd_list, gpd_list_node) { + if (gpd->provider == &np->fwnode) { gpd->has_provider = false; + if (!gpd->set_performance_state) + continue; + + dev_pm_opp_of_remove_table(&gpd->dev); + } + } + list_del(&cp->link); of_node_put(cp->node); kfree(cp); @@ -2185,31 +2228,25 @@ static void genpd_dev_pm_sync(struct device *dev) * Parse device's OF node to find a PM domain specifier. If such is found, * attaches the device to retrieved pm_domain ops. * - * Both generic and legacy Samsung-specific DT bindings are supported to keep - * backwards compatibility with existing DTBs. - * - * Returns 0 on successfully attached PM domain or negative error code. Note - * that if a power-domain exists for the device, but it cannot be found or - * turned on, then return -EPROBE_DEFER to ensure that the device is not - * probed and to re-try again later. + * Returns 1 on successfully attached PM domain, 0 when the device don't need a + * PM domain or a negative error code in case of failures. Note that if a + * power-domain exists for the device, but it cannot be found or turned on, + * then return -EPROBE_DEFER to ensure that the device is not probed and to + * re-try again later. */ int genpd_dev_pm_attach(struct device *dev) { struct of_phandle_args pd_args; struct generic_pm_domain *pd; - unsigned int i; int ret; if (!dev->of_node) - return -ENODEV; - - if (dev->pm_domain) - return -EEXIST; + return 0; ret = of_parse_phandle_with_args(dev->of_node, "power-domains", "#power-domain-cells", 0, &pd_args); if (ret < 0) - return ret; + return 0; mutex_lock(&gpd_list_lock); pd = genpd_get_from_provider(&pd_args); @@ -2223,21 +2260,14 @@ int genpd_dev_pm_attach(struct device *dev) dev_dbg(dev, "adding to PM domain %s\n", pd->name); - for (i = 1; i < GENPD_RETRY_MAX_MS; i <<= 1) { - ret = genpd_add_device(pd, dev, NULL); - if (ret != -EAGAIN) - break; - - mdelay(i); - cond_resched(); - } + ret = genpd_add_device(pd, dev, NULL); mutex_unlock(&gpd_list_lock); if (ret < 0) { if (ret != -EPROBE_DEFER) dev_err(dev, "failed to add to PM domain %s: %d", pd->name, ret); - goto out; + return ret; } dev->pm_domain->detach = genpd_dev_pm_detach; @@ -2246,8 +2276,11 @@ int genpd_dev_pm_attach(struct device *dev) genpd_lock(pd); ret = genpd_power_on(pd, 0); genpd_unlock(pd); -out: - return ret ? -EPROBE_DEFER : 0; + + if (ret) + genpd_remove_device(pd, dev); + + return ret ? -EPROBE_DEFER : 1; } EXPORT_SYMBOL_GPL(genpd_dev_pm_attach); @@ -2361,6 +2394,55 @@ int of_genpd_parse_idle_states(struct device_node *dn, } EXPORT_SYMBOL_GPL(of_genpd_parse_idle_states); +/** + * of_genpd_opp_to_performance_state- Gets performance state of device's + * power domain corresponding to a DT node's "required-opps" property. + * + * @dev: Device for which the performance-state needs to be found. + * @opp_node: DT node where the "required-opps" property is present. This can be + * the device node itself (if it doesn't have an OPP table) or a node + * within the OPP table of a device (if device has an OPP table). + * @state: Pointer to return performance state. + * + * Returns performance state corresponding to the "required-opps" property of + * a DT node. This calls platform specific genpd->opp_to_performance_state() + * callback to translate power domain OPP to performance state. + * + * Returns performance state on success and 0 on failure. + */ +unsigned int of_genpd_opp_to_performance_state(struct device *dev, + struct device_node *opp_node) +{ + struct generic_pm_domain *genpd; + struct dev_pm_opp *opp; + int state = 0; + + genpd = dev_to_genpd(dev); + if (IS_ERR(genpd)) + return 0; + + if (unlikely(!genpd->set_performance_state)) + return 0; + + genpd_lock(genpd); + + opp = of_dev_pm_opp_find_required_opp(&genpd->dev, opp_node); + if (IS_ERR(opp)) { + dev_err(dev, "Failed to find required OPP: %ld\n", + PTR_ERR(opp)); + goto unlock; + } + + state = genpd->opp_to_performance_state(genpd, opp); + dev_pm_opp_put(opp); + +unlock: + genpd_unlock(genpd); + + return state; +} +EXPORT_SYMBOL_GPL(of_genpd_opp_to_performance_state); + #endif /* CONFIG_PM_GENERIC_DOMAINS_OF */ @@ -2628,6 +2710,19 @@ static int genpd_devices_show(struct seq_file *s, void *data) return ret; } +static int genpd_perf_state_show(struct seq_file *s, void *data) +{ + struct generic_pm_domain *genpd = s->private; + + if (genpd_lock_interruptible(genpd)) + return -ERESTARTSYS; + + seq_printf(s, "%u\n", genpd->performance_state); + + genpd_unlock(genpd); + return 0; +} + #define define_genpd_open_function(name) \ static int genpd_##name##_open(struct inode *inode, struct file *file) \ { \ @@ -2641,6 +2736,7 @@ define_genpd_open_function(idle_states); define_genpd_open_function(active_time); define_genpd_open_function(total_idle_time); define_genpd_open_function(devices); +define_genpd_open_function(perf_state); #define define_genpd_debugfs_fops(name) \ static const struct file_operations genpd_##name##_fops = { \ @@ -2657,6 +2753,7 @@ define_genpd_debugfs_fops(idle_states); define_genpd_debugfs_fops(active_time); define_genpd_debugfs_fops(total_idle_time); define_genpd_debugfs_fops(devices); +define_genpd_debugfs_fops(perf_state); static int __init genpd_debug_init(void) { @@ -2690,6 +2787,9 @@ static int __init genpd_debug_init(void) d, genpd, &genpd_total_idle_time_fops); debugfs_create_file("devices", 0444, d, genpd, &genpd_devices_fops); + if (genpd->set_performance_state) + debugfs_create_file("perf_state", 0444, + d, genpd, &genpd_perf_state_fops); } return 0; diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 02a497e7c785..3f68e2919dc5 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -192,34 +192,31 @@ void device_pm_move_last(struct device *dev) list_move_tail(&dev->power.entry, &dpm_list); } -static ktime_t initcall_debug_start(struct device *dev) +static ktime_t initcall_debug_start(struct device *dev, void *cb) { - ktime_t calltime = 0; - - if (pm_print_times_enabled) { - pr_info("calling %s+ @ %i, parent: %s\n", - dev_name(dev), task_pid_nr(current), - dev->parent ? dev_name(dev->parent) : "none"); - calltime = ktime_get(); - } + if (!pm_print_times_enabled) + return 0; - return calltime; + dev_info(dev, "calling %pF @ %i, parent: %s\n", cb, + task_pid_nr(current), + dev->parent ? dev_name(dev->parent) : "none"); + return ktime_get(); } static void initcall_debug_report(struct device *dev, ktime_t calltime, - int error, pm_message_t state, - const char *info) + void *cb, int error) { ktime_t rettime; s64 nsecs; + if (!pm_print_times_enabled) + return; + rettime = ktime_get(); nsecs = (s64) ktime_to_ns(ktime_sub(rettime, calltime)); - if (pm_print_times_enabled) { - pr_info("call %s+ returned %d after %Ld usecs\n", dev_name(dev), - error, (unsigned long long)nsecs >> 10); - } + dev_info(dev, "%pF returned %d after %Ld usecs\n", cb, error, + (unsigned long long)nsecs >> 10); } /** @@ -446,7 +443,7 @@ static int dpm_run_callback(pm_callback_t cb, struct device *dev, if (!cb) return 0; - calltime = initcall_debug_start(dev); + calltime = initcall_debug_start(dev, cb); pm_dev_dbg(dev, state, info); trace_device_pm_callback_start(dev, info, state.event); @@ -454,7 +451,7 @@ static int dpm_run_callback(pm_callback_t cb, struct device *dev, trace_device_pm_callback_end(dev, error); suspend_report_result(cb, error); - initcall_debug_report(dev, calltime, error, state, info); + initcall_debug_report(dev, calltime, cb, error); return error; } @@ -1664,14 +1661,14 @@ static int legacy_suspend(struct device *dev, pm_message_t state, int error; ktime_t calltime; - calltime = initcall_debug_start(dev); + calltime = initcall_debug_start(dev, cb); trace_device_pm_callback_start(dev, info, state.event); error = cb(dev, state); trace_device_pm_callback_end(dev, error); suspend_report_result(cb, error); - initcall_debug_report(dev, calltime, error, state, info); + initcall_debug_report(dev, calltime, cb, error); return error; } @@ -1923,10 +1920,8 @@ static int device_prepare(struct device *dev, pm_message_t state) dev->power.wakeup_path = false; - if (dev->power.no_pm_callbacks) { - ret = 1; /* Let device go direct_complete */ + if (dev->power.no_pm_callbacks) goto unlock; - } if (dev->pm_domain) callback = dev->pm_domain->ops.prepare; @@ -1960,7 +1955,8 @@ unlock: */ spin_lock_irq(&dev->power.lock); dev->power.direct_complete = state.event == PM_EVENT_SUSPEND && - pm_runtime_suspended(dev) && ret > 0 && + ((pm_runtime_suspended(dev) && ret > 0) || + dev->power.no_pm_callbacks) && !dev_pm_test_driver_flags(dev, DPM_FLAG_NEVER_SKIP); spin_unlock_irq(&dev->power.lock); return 0; diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index 86e67e70b509..c511def48b48 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h @@ -56,14 +56,6 @@ static inline void device_wakeup_detach_irq(struct device *dev) { } -static inline void device_wakeup_arm_wake_irqs(void) -{ -} - -static inline void device_wakeup_disarm_wake_irqs(void) -{ -} - #endif /* CONFIG_PM_SLEEP */ /* @@ -95,28 +87,6 @@ static inline void pm_runtime_remove(struct device *dev) {} static inline int dpm_sysfs_add(struct device *dev) { return 0; } static inline void dpm_sysfs_remove(struct device *dev) {} -static inline void rpm_sysfs_remove(struct device *dev) {} -static inline int wakeup_sysfs_add(struct device *dev) { return 0; } -static inline void wakeup_sysfs_remove(struct device *dev) {} -static inline int pm_qos_sysfs_add(struct device *dev) { return 0; } -static inline void pm_qos_sysfs_remove(struct device *dev) {} - -static inline void dev_pm_arm_wake_irq(struct wake_irq *wirq) -{ -} - -static inline void dev_pm_disarm_wake_irq(struct wake_irq *wirq) -{ -} - -static inline void dev_pm_enable_wake_irq_check(struct device *dev, - bool can_change_status) -{ -} - -static inline void dev_pm_disable_wake_irq_check(struct device *dev) -{ -} #endif diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 8bef3cb2424d..c6030f100c08 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -1563,37 +1563,16 @@ void pm_runtime_clean_up_links(struct device *dev) } /** - * pm_runtime_get_suppliers - Resume and reference-count supplier devices. + * pm_runtime_resume_suppliers - Resume supplier devices. * @dev: Consumer device. */ -void pm_runtime_get_suppliers(struct device *dev) +void pm_runtime_resume_suppliers(struct device *dev) { - struct device_link *link; - int idx; - - idx = device_links_read_lock(); - - list_for_each_entry_rcu(link, &dev->links.suppliers, c_node) - if (link->flags & DL_FLAG_PM_RUNTIME) - pm_runtime_get_sync(link->supplier); - - device_links_read_unlock(idx); -} - -/** - * pm_runtime_put_suppliers - Drop references to supplier devices. - * @dev: Consumer device. - */ -void pm_runtime_put_suppliers(struct device *dev) -{ - struct device_link *link; int idx; idx = device_links_read_lock(); - list_for_each_entry_rcu(link, &dev->links.suppliers, c_node) - if (link->flags & DL_FLAG_PM_RUNTIME) - pm_runtime_put(link->supplier); + rpm_get_suppliers(dev); device_links_read_unlock(idx); } @@ -1607,6 +1586,8 @@ void pm_runtime_new_link(struct device *dev) void pm_runtime_drop_link(struct device *dev) { + rpm_put_suppliers(dev); + spin_lock_irq(&dev->power.lock); WARN_ON(dev->power.links_count == 0); dev->power.links_count--; diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index ea01621ed769..5fa1898755a3 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -57,7 +57,7 @@ static void split_counters(unsigned int *cnt, unsigned int *inpr) /* A preserved old value of the events counter. */ static unsigned int saved_count; -static DEFINE_SPINLOCK(events_lock); +static DEFINE_RAW_SPINLOCK(events_lock); static void pm_wakeup_timer_fn(struct timer_list *t); @@ -183,11 +183,10 @@ void wakeup_source_add(struct wakeup_source *ws) spin_lock_init(&ws->lock); timer_setup(&ws->timer, pm_wakeup_timer_fn, 0); ws->active = false; - ws->last_time = ktime_get(); - spin_lock_irqsave(&events_lock, flags); + raw_spin_lock_irqsave(&events_lock, flags); list_add_rcu(&ws->entry, &wakeup_sources); - spin_unlock_irqrestore(&events_lock, flags); + raw_spin_unlock_irqrestore(&events_lock, flags); } EXPORT_SYMBOL_GPL(wakeup_source_add); @@ -202,9 +201,9 @@ void wakeup_source_remove(struct wakeup_source *ws) if (WARN_ON(!ws)) return; - spin_lock_irqsave(&events_lock, flags); + raw_spin_lock_irqsave(&events_lock, flags); list_del_rcu(&ws->entry); - spin_unlock_irqrestore(&events_lock, flags); + raw_spin_unlock_irqrestore(&events_lock, flags); synchronize_srcu(&wakeup_srcu); } EXPORT_SYMBOL_GPL(wakeup_source_remove); @@ -843,7 +842,7 @@ bool pm_wakeup_pending(void) unsigned long flags; bool ret = false; - spin_lock_irqsave(&events_lock, flags); + raw_spin_lock_irqsave(&events_lock, flags); if (events_check_enabled) { unsigned int cnt, inpr; @@ -851,10 +850,10 @@ bool pm_wakeup_pending(void) ret = (cnt != saved_count || inpr > 0); events_check_enabled = !ret; } - spin_unlock_irqrestore(&events_lock, flags); + raw_spin_unlock_irqrestore(&events_lock, flags); if (ret) { - pr_info("PM: Wakeup pending, aborting suspend\n"); + pr_debug("PM: Wakeup pending, aborting suspend\n"); pm_print_active_wakeup_sources(); } @@ -940,13 +939,13 @@ bool pm_save_wakeup_count(unsigned int count) unsigned long flags; events_check_enabled = false; - spin_lock_irqsave(&events_lock, flags); + raw_spin_lock_irqsave(&events_lock, flags); split_counters(&cnt, &inpr); if (cnt == count && inpr == 0) { saved_count = count; events_check_enabled = true; } - spin_unlock_irqrestore(&events_lock, flags); + raw_spin_unlock_irqrestore(&events_lock, flags); return events_check_enabled; } @@ -1029,32 +1028,75 @@ static int print_wakeup_source_stats(struct seq_file *m, return 0; } -/** - * wakeup_sources_stats_show - Print wakeup sources statistics information. - * @m: seq_file to print the statistics into. - */ -static int wakeup_sources_stats_show(struct seq_file *m, void *unused) +static void *wakeup_sources_stats_seq_start(struct seq_file *m, + loff_t *pos) { struct wakeup_source *ws; - int srcuidx; + loff_t n = *pos; + int *srcuidx = m->private; - seq_puts(m, "name\t\tactive_count\tevent_count\twakeup_count\t" - "expire_count\tactive_since\ttotal_time\tmax_time\t" - "last_change\tprevent_suspend_time\n"); + if (n == 0) { + seq_puts(m, "name\t\tactive_count\tevent_count\twakeup_count\t" + "expire_count\tactive_since\ttotal_time\tmax_time\t" + "last_change\tprevent_suspend_time\n"); + } - srcuidx = srcu_read_lock(&wakeup_srcu); - list_for_each_entry_rcu(ws, &wakeup_sources, entry) - print_wakeup_source_stats(m, ws); - srcu_read_unlock(&wakeup_srcu, srcuidx); + *srcuidx = srcu_read_lock(&wakeup_srcu); + list_for_each_entry_rcu(ws, &wakeup_sources, entry) { + if (n-- <= 0) + return ws; + } + + return NULL; +} + +static void *wakeup_sources_stats_seq_next(struct seq_file *m, + void *v, loff_t *pos) +{ + struct wakeup_source *ws = v; + struct wakeup_source *next_ws = NULL; - print_wakeup_source_stats(m, &deleted_ws); + ++(*pos); + + list_for_each_entry_continue_rcu(ws, &wakeup_sources, entry) { + next_ws = ws; + break; + } + + return next_ws; +} + +static void wakeup_sources_stats_seq_stop(struct seq_file *m, void *v) +{ + int *srcuidx = m->private; + + srcu_read_unlock(&wakeup_srcu, *srcuidx); +} + +/** + * wakeup_sources_stats_seq_show - Print wakeup sources statistics information. + * @m: seq_file to print the statistics into. + * @v: wakeup_source of each iteration + */ +static int wakeup_sources_stats_seq_show(struct seq_file *m, void *v) +{ + struct wakeup_source *ws = v; + + print_wakeup_source_stats(m, ws); return 0; } +static const struct seq_operations wakeup_sources_stats_seq_ops = { + .start = wakeup_sources_stats_seq_start, + .next = wakeup_sources_stats_seq_next, + .stop = wakeup_sources_stats_seq_stop, + .show = wakeup_sources_stats_seq_show, +}; + static int wakeup_sources_stats_open(struct inode *inode, struct file *file) { - return single_open(file, wakeup_sources_stats_show, NULL); + return seq_open_private(file, &wakeup_sources_stats_seq_ops, sizeof(int)); } static const struct file_operations wakeup_sources_stats_fops = { @@ -1062,7 +1104,7 @@ static const struct file_operations wakeup_sources_stats_fops = { .open = wakeup_sources_stats_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release_private, }; static int __init wakeup_sources_debugfs_init(void) diff --git a/drivers/base/property.c b/drivers/base/property.c index 8f205f6461ed..240ab5230ff6 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -56,6 +56,72 @@ pset_prop_get(const struct property_set *pset, const char *name) return NULL; } +static const void *property_get_pointer(const struct property_entry *prop) +{ + switch (prop->type) { + case DEV_PROP_U8: + if (prop->is_array) + return prop->pointer.u8_data; + return &prop->value.u8_data; + case DEV_PROP_U16: + if (prop->is_array) + return prop->pointer.u16_data; + return &prop->value.u16_data; + case DEV_PROP_U32: + if (prop->is_array) + return prop->pointer.u32_data; + return &prop->value.u32_data; + case DEV_PROP_U64: + if (prop->is_array) + return prop->pointer.u64_data; + return &prop->value.u64_data; + case DEV_PROP_STRING: + if (prop->is_array) + return prop->pointer.str; + return &prop->value.str; + default: + return NULL; + } +} + +static void property_set_pointer(struct property_entry *prop, const void *pointer) +{ + switch (prop->type) { + case DEV_PROP_U8: + if (prop->is_array) + prop->pointer.u8_data = pointer; + else + prop->value.u8_data = *((u8 *)pointer); + break; + case DEV_PROP_U16: + if (prop->is_array) + prop->pointer.u16_data = pointer; + else + prop->value.u16_data = *((u16 *)pointer); + break; + case DEV_PROP_U32: + if (prop->is_array) + prop->pointer.u32_data = pointer; + else + prop->value.u32_data = *((u32 *)pointer); + break; + case DEV_PROP_U64: + if (prop->is_array) + prop->pointer.u64_data = pointer; + else + prop->value.u64_data = *((u64 *)pointer); + break; + case DEV_PROP_STRING: + if (prop->is_array) + prop->pointer.str = pointer; + else + prop->value.str = pointer; + break; + default: + break; + } +} + static const void *pset_prop_find(const struct property_set *pset, const char *propname, size_t length) { @@ -65,10 +131,7 @@ static const void *pset_prop_find(const struct property_set *pset, prop = pset_prop_get(pset, propname); if (!prop) return ERR_PTR(-EINVAL); - if (prop->is_array) - pointer = prop->pointer.raw_data; - else - pointer = &prop->value.raw_data; + pointer = property_get_pointer(prop); if (!pointer) return ERR_PTR(-ENODATA); if (length > prop->length) @@ -698,16 +761,17 @@ EXPORT_SYMBOL_GPL(fwnode_property_get_reference_args); static void property_entry_free_data(const struct property_entry *p) { + const void *pointer = property_get_pointer(p); size_t i, nval; if (p->is_array) { - if (p->is_string && p->pointer.str) { + if (p->type == DEV_PROP_STRING && p->pointer.str) { nval = p->length / sizeof(const char *); for (i = 0; i < nval; i++) kfree(p->pointer.str[i]); } - kfree(p->pointer.raw_data); - } else if (p->is_string) { + kfree(pointer); + } else if (p->type == DEV_PROP_STRING) { kfree(p->value.str); } kfree(p->name); @@ -716,7 +780,7 @@ static void property_entry_free_data(const struct property_entry *p) static int property_copy_string_array(struct property_entry *dst, const struct property_entry *src) { - char **d; + const char **d; size_t nval = src->length / sizeof(*d); int i; @@ -734,40 +798,44 @@ static int property_copy_string_array(struct property_entry *dst, } } - dst->pointer.raw_data = d; + dst->pointer.str = d; return 0; } static int property_entry_copy_data(struct property_entry *dst, const struct property_entry *src) { + const void *pointer = property_get_pointer(src); + const void *new; int error; if (src->is_array) { if (!src->length) return -ENODATA; - if (src->is_string) { + if (src->type == DEV_PROP_STRING) { error = property_copy_string_array(dst, src); if (error) return error; + new = dst->pointer.str; } else { - dst->pointer.raw_data = kmemdup(src->pointer.raw_data, - src->length, GFP_KERNEL); - if (!dst->pointer.raw_data) + new = kmemdup(pointer, src->length, GFP_KERNEL); + if (!new) return -ENOMEM; } - } else if (src->is_string) { - dst->value.str = kstrdup(src->value.str, GFP_KERNEL); - if (!dst->value.str && src->value.str) + } else if (src->type == DEV_PROP_STRING) { + new = kstrdup(src->value.str, GFP_KERNEL); + if (!new && src->value.str) return -ENOMEM; } else { - dst->value.raw_data = src->value.raw_data; + new = pointer; } dst->length = src->length; dst->is_array = src->is_array; - dst->is_string = src->is_string; + dst->type = src->type; + + property_set_pointer(dst, new); dst->name = kstrdup(src->name, GFP_KERNEL); if (!dst->name) diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c index 5cadfd3394d8..8741fb5f8f54 100644 --- a/drivers/base/regmap/regmap-mmio.c +++ b/drivers/base/regmap/regmap-mmio.c @@ -206,7 +206,8 @@ static void regmap_mmio_free_context(void *context) if (!IS_ERR(ctx->clk)) { clk_unprepare(ctx->clk); - clk_put(ctx->clk); + if (!ctx->attached_clk) + clk_put(ctx->clk); } kfree(context); } diff --git a/drivers/base/regmap/regmap-slimbus.c b/drivers/base/regmap/regmap-slimbus.c index c90bee81d954..91d501eda8a9 100644 --- a/drivers/base/regmap/regmap-slimbus.c +++ b/drivers/base/regmap/regmap-slimbus.c @@ -41,7 +41,7 @@ static struct regmap_bus regmap_slimbus_bus = { static const struct regmap_bus *regmap_get_slimbus(struct slim_device *slim, const struct regmap_config *config) { - if (config->val_bits == 8 && config->reg_bits == 8) + if (config->val_bits == 8 && config->reg_bits == 16) return ®map_slimbus_bus; return ERR_PTR(-ENOTSUPP); diff --git a/drivers/bcma/driver_mips.c b/drivers/bcma/driver_mips.c index f040aba48d50..27e9686b6d3a 100644 --- a/drivers/bcma/driver_mips.c +++ b/drivers/bcma/driver_mips.c @@ -184,7 +184,7 @@ static void bcma_core_mips_print_irq(struct bcma_device *dev, unsigned int irq) { int i; static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"}; - char interrupts[20]; + char interrupts[25]; char *ints = interrupts; for (i = 0; i < ARRAY_SIZE(irq_name); i++) diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index e6986c7608f1..fc1f4acdd189 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -207,7 +207,7 @@ static void bcma_of_fill_device(struct device *parent, core->irq = bcma_of_get_irq(parent, core, 0); - of_dma_configure(&core->dev, node); + of_dma_configure(&core->dev, node, false); } unsigned int bcma_core_irq(struct bcma_device *core, int num) diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index f781eff7d23e..6ca77d6047d6 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -1179,7 +1179,6 @@ static bool DAC960_V1_EnableMemoryMailboxInterface(DAC960_Controller_T if (pci_set_dma_mask(Controller->PCIDevice, DMA_BIT_MASK(32))) return DAC960_Failure(Controller, "DMA mask out of range"); - Controller->BounceBufferLimit = DMA_BIT_MASK(32); if ((hw_type == DAC960_PD_Controller) || (hw_type == DAC960_P_Controller)) { CommandMailboxesSize = 0; @@ -1380,11 +1379,8 @@ static bool DAC960_V2_EnableMemoryMailboxInterface(DAC960_Controller_T dma_addr_t CommandMailboxDMA; DAC960_V2_CommandStatus_T CommandStatus; - if (!pci_set_dma_mask(Controller->PCIDevice, DMA_BIT_MASK(64))) - Controller->BounceBufferLimit = DMA_BIT_MASK(64); - else if (!pci_set_dma_mask(Controller->PCIDevice, DMA_BIT_MASK(32))) - Controller->BounceBufferLimit = DMA_BIT_MASK(32); - else + if (pci_set_dma_mask(Controller->PCIDevice, DMA_BIT_MASK(64)) && + pci_set_dma_mask(Controller->PCIDevice, DMA_BIT_MASK(32))) return DAC960_Failure(Controller, "DMA mask out of range"); /* This is a temporary dma mapping, used only in the scope of this function */ @@ -2540,7 +2536,6 @@ static bool DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller) continue; } Controller->RequestQueue[n] = RequestQueue; - blk_queue_bounce_limit(RequestQueue, Controller->BounceBufferLimit); RequestQueue->queuedata = Controller; blk_queue_max_segments(RequestQueue, Controller->DriverScatterGatherLimit); blk_queue_max_hw_sectors(RequestQueue, Controller->MaxBlocksPerCommand); @@ -6451,19 +6446,6 @@ static int dac960_proc_show(struct seq_file *m, void *v) return 0; } -static int dac960_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, dac960_proc_show, NULL); -} - -static const struct file_operations dac960_proc_fops = { - .owner = THIS_MODULE, - .open = dac960_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static int dac960_initial_status_proc_show(struct seq_file *m, void *v) { DAC960_Controller_T *Controller = (DAC960_Controller_T *)m->private; @@ -6471,19 +6453,6 @@ static int dac960_initial_status_proc_show(struct seq_file *m, void *v) return 0; } -static int dac960_initial_status_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, dac960_initial_status_proc_show, PDE_DATA(inode)); -} - -static const struct file_operations dac960_initial_status_proc_fops = { - .owner = THIS_MODULE, - .open = dac960_initial_status_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static int dac960_current_status_proc_show(struct seq_file *m, void *v) { DAC960_Controller_T *Controller = (DAC960_Controller_T *) m->private; @@ -6517,19 +6486,6 @@ static int dac960_current_status_proc_show(struct seq_file *m, void *v) return 0; } -static int dac960_current_status_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, dac960_current_status_proc_show, PDE_DATA(inode)); -} - -static const struct file_operations dac960_current_status_proc_fops = { - .owner = THIS_MODULE, - .open = dac960_current_status_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static int dac960_user_command_proc_show(struct seq_file *m, void *v) { DAC960_Controller_T *Controller = (DAC960_Controller_T *)m->private; @@ -6584,17 +6540,19 @@ static void DAC960_CreateProcEntries(DAC960_Controller_T *Controller) if (DAC960_ProcDirectoryEntry == NULL) { DAC960_ProcDirectoryEntry = proc_mkdir("rd", NULL); - proc_create("status", 0, DAC960_ProcDirectoryEntry, - &dac960_proc_fops); + proc_create_single("status", 0, DAC960_ProcDirectoryEntry, + dac960_proc_show); } snprintf(Controller->ControllerName, sizeof(Controller->ControllerName), "c%d", Controller->ControllerNumber); ControllerProcEntry = proc_mkdir(Controller->ControllerName, DAC960_ProcDirectoryEntry); - proc_create_data("initial_status", 0, ControllerProcEntry, &dac960_initial_status_proc_fops, Controller); - proc_create_data("current_status", 0, ControllerProcEntry, &dac960_current_status_proc_fops, Controller); - proc_create_data("user_command", S_IWUSR | S_IRUSR, ControllerProcEntry, &dac960_user_command_proc_fops, Controller); + proc_create_single_data("initial_status", 0, ControllerProcEntry, + dac960_initial_status_proc_show, Controller); + proc_create_single_data("current_status", 0, ControllerProcEntry, + dac960_current_status_proc_show, Controller); + proc_create_data("user_command", 0600, ControllerProcEntry, &dac960_user_command_proc_fops, Controller); Controller->ControllerProcEntry = ControllerProcEntry; } diff --git a/drivers/block/DAC960.h b/drivers/block/DAC960.h index 21aff470d268..1439e651928b 100644 --- a/drivers/block/DAC960.h +++ b/drivers/block/DAC960.h @@ -2295,7 +2295,6 @@ typedef struct DAC960_Controller unsigned short MaxBlocksPerCommand; unsigned short ControllerScatterGatherLimit; unsigned short DriverScatterGatherLimit; - u64 BounceBufferLimit; unsigned int CombinedStatusBufferLength; unsigned int InitialStatusLength; unsigned int CurrentStatusLength; diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index 6797e6c23c8a..429ebb84b592 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -159,14 +159,14 @@ static int aoe_debugfs_open(struct inode *inode, struct file *file) return single_open(file, aoedisk_debugfs_show, inode->i_private); } -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 DEVICE_ATTR(state, 0444, aoedisk_show_state, NULL); +static DEVICE_ATTR(mac, 0444, aoedisk_show_mac, NULL); +static DEVICE_ATTR(netif, 0444, aoedisk_show_netif, NULL); static struct device_attribute dev_attr_firmware_version = { - .attr = { .name = "firmware-version", .mode = S_IRUGO }, + .attr = { .name = "firmware-version", .mode = 0444 }, .show = aoedisk_show_fwver, }; -static DEVICE_ATTR(payload, S_IRUGO, aoedisk_show_payload, NULL); +static DEVICE_ATTR(payload, 0444, aoedisk_show_payload, NULL); static struct attribute *aoe_attrs[] = { &dev_attr_state.attr, @@ -388,7 +388,6 @@ aoeblk_gdalloc(void *vp) d->aoemajor, d->aoeminor); goto err_mempool; } - blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH); spin_lock_irqsave(&d->lock, flags); WARN_ON(!(d->flags & DEVFL_GD_NOW)); diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 540bb60cd071..096882e54095 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -1032,8 +1032,9 @@ bvcpy(struct sk_buff *skb, struct bio *bio, struct bvec_iter iter, long cnt) iter.bi_size = cnt; __bio_for_each_segment(bv, bio, iter, iter) { - char *p = page_address(bv.bv_page) + bv.bv_offset; + char *p = kmap_atomic(bv.bv_page) + bv.bv_offset; skb_copy_bits(skb, soff, p, bv.bv_len); + kunmap_atomic(p); soff += bv.bv_len; } } diff --git a/drivers/block/brd.c b/drivers/block/brd.c index 66cb0f857f64..bb976598ee43 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -331,15 +331,15 @@ static const struct block_device_operations brd_fops = { * And now the modules code and kernel interface. */ static int rd_nr = CONFIG_BLK_DEV_RAM_COUNT; -module_param(rd_nr, int, S_IRUGO); +module_param(rd_nr, int, 0444); MODULE_PARM_DESC(rd_nr, "Maximum number of brd devices"); unsigned long rd_size = CONFIG_BLK_DEV_RAM_SIZE; -module_param(rd_size, ulong, S_IRUGO); +module_param(rd_size, ulong, 0444); MODULE_PARM_DESC(rd_size, "Size of each RAM disk in kbytes."); static int max_part = 1; -module_param(max_part, int, S_IRUGO); +module_param(max_part, int, 0444); MODULE_PARM_DESC(max_part, "Num Minors to reserve between devices"); MODULE_LICENSE("GPL"); @@ -402,6 +402,10 @@ static struct brd_device *brd_alloc(int i) set_capacity(disk, rd_size * 2); disk->queue->backing_dev_info->capabilities |= BDI_CAP_SYNCHRONOUS_IO; + /* Tell the block layer that this is not a rotational device */ + blk_queue_flag_set(QUEUE_FLAG_NONROT, disk->queue); + blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, disk->queue); + return brd; out_free_queue: diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index 9f4e6f502b84..11a85b740327 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -977,7 +977,7 @@ static void drbd_bm_endio(struct bio *bio) bm_page_unlock_io(device, idx); if (ctx->flags & BM_AIO_COPY_PAGES) - mempool_free(bio->bi_io_vec[0].bv_page, drbd_md_io_page_pool); + mempool_free(bio->bi_io_vec[0].bv_page, &drbd_md_io_page_pool); bio_put(bio); @@ -1014,7 +1014,8 @@ static void bm_page_io_async(struct drbd_bm_aio_ctx *ctx, int page_nr) __must_ho bm_set_page_unchanged(b->bm_pages[page_nr]); if (ctx->flags & BM_AIO_COPY_PAGES) { - page = mempool_alloc(drbd_md_io_page_pool, __GFP_HIGHMEM|__GFP_RECLAIM); + page = mempool_alloc(&drbd_md_io_page_pool, + GFP_NOIO | __GFP_HIGHMEM); copy_highpage(page, b->bm_pages[page_nr]); bm_store_page_idx(page, page_nr); } else diff --git a/drivers/block/drbd/drbd_debugfs.c b/drivers/block/drbd/drbd_debugfs.c index ab21976a87b2..5d5e8d6a8a56 100644 --- a/drivers/block/drbd/drbd_debugfs.c +++ b/drivers/block/drbd/drbd_debugfs.c @@ -481,9 +481,9 @@ void drbd_debugfs_resource_add(struct drbd_resource *resource) goto fail; resource->debugfs_res_connections = dentry; - dentry = debugfs_create_file("in_flight_summary", S_IRUSR|S_IRGRP, - resource->debugfs_res, resource, - &in_flight_summary_fops); + dentry = debugfs_create_file("in_flight_summary", 0440, + resource->debugfs_res, resource, + &in_flight_summary_fops); if (IS_ERR_OR_NULL(dentry)) goto fail; resource->debugfs_res_in_flight_summary = dentry; @@ -645,16 +645,16 @@ void drbd_debugfs_connection_add(struct drbd_connection *connection) goto fail; connection->debugfs_conn = dentry; - dentry = debugfs_create_file("callback_history", S_IRUSR|S_IRGRP, - connection->debugfs_conn, connection, - &connection_callback_history_fops); + dentry = debugfs_create_file("callback_history", 0440, + connection->debugfs_conn, connection, + &connection_callback_history_fops); if (IS_ERR_OR_NULL(dentry)) goto fail; connection->debugfs_conn_callback_history = dentry; - dentry = debugfs_create_file("oldest_requests", S_IRUSR|S_IRGRP, - connection->debugfs_conn, connection, - &connection_oldest_requests_fops); + dentry = debugfs_create_file("oldest_requests", 0440, + connection->debugfs_conn, connection, + &connection_oldest_requests_fops); if (IS_ERR_OR_NULL(dentry)) goto fail; connection->debugfs_conn_oldest_requests = dentry; @@ -824,7 +824,7 @@ void drbd_debugfs_device_add(struct drbd_device *device) device->debugfs_minor = dentry; #define DCF(name) do { \ - dentry = debugfs_create_file(#name, S_IRUSR|S_IRGRP, \ + dentry = debugfs_create_file(#name, 0440, \ device->debugfs_vol, device, \ &device_ ## name ## _fops); \ if (IS_ERR_OR_NULL(dentry)) \ diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 06ecee1b528e..bc4ed2ed40a2 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1405,8 +1405,8 @@ extern struct kmem_cache *drbd_request_cache; extern struct kmem_cache *drbd_ee_cache; /* peer requests */ extern struct kmem_cache *drbd_bm_ext_cache; /* bitmap extents */ extern struct kmem_cache *drbd_al_ext_cache; /* activity log extents */ -extern mempool_t *drbd_request_mempool; -extern mempool_t *drbd_ee_mempool; +extern mempool_t drbd_request_mempool; +extern mempool_t drbd_ee_mempool; /* drbd's page pool, used to buffer data received from the peer, * or data requested by the peer. @@ -1432,16 +1432,16 @@ extern wait_queue_head_t drbd_pp_wait; * 128 should be plenty, currently we probably can get away with as few as 1. */ #define DRBD_MIN_POOL_PAGES 128 -extern mempool_t *drbd_md_io_page_pool; +extern mempool_t drbd_md_io_page_pool; /* We also need to make sure we get a bio * when we need it for housekeeping purposes */ -extern struct bio_set *drbd_md_io_bio_set; +extern struct bio_set drbd_md_io_bio_set; /* to allocate from that set */ extern struct bio *bio_alloc_drbd(gfp_t gfp_mask); /* And a bio_set for cloning */ -extern struct bio_set *drbd_io_bio_set; +extern struct bio_set drbd_io_bio_set; extern struct mutex resources_mutex; @@ -1643,7 +1643,7 @@ void drbd_bump_write_ordering(struct drbd_resource *resource, struct drbd_backin /* drbd_proc.c */ extern struct proc_dir_entry *drbd_proc; -extern const struct file_operations drbd_proc_fops; +int drbd_seq_show(struct seq_file *seq, void *v); /* drbd_actlog.c */ extern bool drbd_al_begin_io_prepare(struct drbd_device *device, struct drbd_interval *i); diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 185f1ef00a7c..7655d6133139 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -124,11 +124,11 @@ struct kmem_cache *drbd_request_cache; struct kmem_cache *drbd_ee_cache; /* peer requests */ struct kmem_cache *drbd_bm_ext_cache; /* bitmap extents */ struct kmem_cache *drbd_al_ext_cache; /* activity log extents */ -mempool_t *drbd_request_mempool; -mempool_t *drbd_ee_mempool; -mempool_t *drbd_md_io_page_pool; -struct bio_set *drbd_md_io_bio_set; -struct bio_set *drbd_io_bio_set; +mempool_t drbd_request_mempool; +mempool_t drbd_ee_mempool; +mempool_t drbd_md_io_page_pool; +struct bio_set drbd_md_io_bio_set; +struct bio_set drbd_io_bio_set; /* I do not use a standard mempool, because: 1) I want to hand out the pre-allocated objects first. @@ -153,10 +153,10 @@ struct bio *bio_alloc_drbd(gfp_t gfp_mask) { struct bio *bio; - if (!drbd_md_io_bio_set) + if (!bioset_initialized(&drbd_md_io_bio_set)) return bio_alloc(gfp_mask, 1); - bio = bio_alloc_bioset(gfp_mask, 1, drbd_md_io_bio_set); + bio = bio_alloc_bioset(gfp_mask, 1, &drbd_md_io_bio_set); if (!bio) return NULL; return bio; @@ -2097,16 +2097,11 @@ static void drbd_destroy_mempools(void) /* D_ASSERT(device, atomic_read(&drbd_pp_vacant)==0); */ - if (drbd_io_bio_set) - bioset_free(drbd_io_bio_set); - if (drbd_md_io_bio_set) - bioset_free(drbd_md_io_bio_set); - if (drbd_md_io_page_pool) - mempool_destroy(drbd_md_io_page_pool); - if (drbd_ee_mempool) - mempool_destroy(drbd_ee_mempool); - if (drbd_request_mempool) - mempool_destroy(drbd_request_mempool); + bioset_exit(&drbd_io_bio_set); + bioset_exit(&drbd_md_io_bio_set); + mempool_exit(&drbd_md_io_page_pool); + mempool_exit(&drbd_ee_mempool); + mempool_exit(&drbd_request_mempool); if (drbd_ee_cache) kmem_cache_destroy(drbd_ee_cache); if (drbd_request_cache) @@ -2116,11 +2111,6 @@ static void drbd_destroy_mempools(void) if (drbd_al_ext_cache) kmem_cache_destroy(drbd_al_ext_cache); - drbd_io_bio_set = NULL; - drbd_md_io_bio_set = NULL; - drbd_md_io_page_pool = NULL; - drbd_ee_mempool = NULL; - drbd_request_mempool = NULL; drbd_ee_cache = NULL; drbd_request_cache = NULL; drbd_bm_ext_cache = NULL; @@ -2133,18 +2123,7 @@ static int drbd_create_mempools(void) { struct page *page; const int number = (DRBD_MAX_BIO_SIZE/PAGE_SIZE) * drbd_minor_count; - int i; - - /* prepare our caches and mempools */ - drbd_request_mempool = NULL; - drbd_ee_cache = NULL; - drbd_request_cache = NULL; - drbd_bm_ext_cache = NULL; - drbd_al_ext_cache = NULL; - drbd_pp_pool = NULL; - drbd_md_io_page_pool = NULL; - drbd_md_io_bio_set = NULL; - drbd_io_bio_set = NULL; + int i, ret; /* caches */ drbd_request_cache = kmem_cache_create( @@ -2168,26 +2147,26 @@ static int drbd_create_mempools(void) goto Enomem; /* mempools */ - drbd_io_bio_set = bioset_create(BIO_POOL_SIZE, 0, 0); - if (drbd_io_bio_set == NULL) + ret = bioset_init(&drbd_io_bio_set, BIO_POOL_SIZE, 0, 0); + if (ret) goto Enomem; - drbd_md_io_bio_set = bioset_create(DRBD_MIN_POOL_PAGES, 0, - BIOSET_NEED_BVECS); - if (drbd_md_io_bio_set == NULL) + ret = bioset_init(&drbd_md_io_bio_set, DRBD_MIN_POOL_PAGES, 0, + BIOSET_NEED_BVECS); + if (ret) goto Enomem; - drbd_md_io_page_pool = mempool_create_page_pool(DRBD_MIN_POOL_PAGES, 0); - if (drbd_md_io_page_pool == NULL) + ret = mempool_init_page_pool(&drbd_md_io_page_pool, DRBD_MIN_POOL_PAGES, 0); + if (ret) goto Enomem; - drbd_request_mempool = mempool_create_slab_pool(number, - drbd_request_cache); - if (drbd_request_mempool == NULL) + ret = mempool_init_slab_pool(&drbd_request_mempool, number, + drbd_request_cache); + if (ret) goto Enomem; - drbd_ee_mempool = mempool_create_slab_pool(number, drbd_ee_cache); - if (drbd_ee_mempool == NULL) + ret = mempool_init_slab_pool(&drbd_ee_mempool, number, drbd_ee_cache); + if (ret) goto Enomem; /* drbd's page pool */ @@ -3010,7 +2989,7 @@ static int __init drbd_init(void) goto fail; err = -ENOMEM; - drbd_proc = proc_create_data("drbd", S_IFREG | S_IRUGO , NULL, &drbd_proc_fops, NULL); + drbd_proc = proc_create_single("drbd", S_IFREG | 0444 , NULL, drbd_seq_show); if (!drbd_proc) { pr_err("unable to register proc file\n"); goto fail; diff --git a/drivers/block/drbd/drbd_proc.c b/drivers/block/drbd/drbd_proc.c index 582caeb0de86..74ef29247bb5 100644 --- a/drivers/block/drbd/drbd_proc.c +++ b/drivers/block/drbd/drbd_proc.c @@ -33,18 +33,7 @@ #include <linux/drbd.h> #include "drbd_int.h" -static int drbd_proc_open(struct inode *inode, struct file *file); -static int drbd_proc_release(struct inode *inode, struct file *file); - - struct proc_dir_entry *drbd_proc; -const struct file_operations drbd_proc_fops = { - .owner = THIS_MODULE, - .open = drbd_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = drbd_proc_release, -}; static void seq_printf_with_thousands_grouping(struct seq_file *seq, long v) { @@ -235,7 +224,7 @@ static void drbd_syncer_progress(struct drbd_device *device, struct seq_file *se } } -static int drbd_seq_show(struct seq_file *seq, void *v) +int drbd_seq_show(struct seq_file *seq, void *v) { int i, prev_i = -1; const char *sn; @@ -345,24 +334,3 @@ static int drbd_seq_show(struct seq_file *seq, void *v) return 0; } - -static int drbd_proc_open(struct inode *inode, struct file *file) -{ - int err; - - if (try_module_get(THIS_MODULE)) { - err = single_open(file, drbd_seq_show, NULL); - if (err) - module_put(THIS_MODULE); - return err; - } - return -ENODEV; -} - -static int drbd_proc_release(struct inode *inode, struct file *file) -{ - module_put(THIS_MODULE); - return single_release(inode, file); -} - -/* PROC FS stuff end */ diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index c72dee0ef083..be9450f5ad1c 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -378,7 +378,7 @@ drbd_alloc_peer_req(struct drbd_peer_device *peer_device, u64 id, sector_t secto if (drbd_insert_fault(device, DRBD_FAULT_AL_EE)) return NULL; - peer_req = mempool_alloc(drbd_ee_mempool, gfp_mask & ~__GFP_HIGHMEM); + peer_req = mempool_alloc(&drbd_ee_mempool, gfp_mask & ~__GFP_HIGHMEM); if (!peer_req) { if (!(gfp_mask & __GFP_NOWARN)) drbd_err(device, "%s: allocation failed\n", __func__); @@ -409,7 +409,7 @@ drbd_alloc_peer_req(struct drbd_peer_device *peer_device, u64 id, sector_t secto return peer_req; fail: - mempool_free(peer_req, drbd_ee_mempool); + mempool_free(peer_req, &drbd_ee_mempool); return NULL; } @@ -426,7 +426,7 @@ void __drbd_free_peer_req(struct drbd_device *device, struct drbd_peer_request * peer_req->flags &= ~EE_CALL_AL_COMPLETE_IO; drbd_al_complete_io(device, &peer_req->i); } - mempool_free(peer_req, drbd_ee_mempool); + mempool_free(peer_req, &drbd_ee_mempool); } int drbd_free_peer_reqs(struct drbd_device *device, struct list_head *list) diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index a500e738d929..a47e4987ee46 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -55,7 +55,7 @@ static struct drbd_request *drbd_req_new(struct drbd_device *device, struct bio { struct drbd_request *req; - req = mempool_alloc(drbd_request_mempool, GFP_NOIO); + req = mempool_alloc(&drbd_request_mempool, GFP_NOIO); if (!req) return NULL; memset(req, 0, sizeof(*req)); @@ -184,7 +184,7 @@ void drbd_req_destroy(struct kref *kref) } } - mempool_free(req, drbd_request_mempool); + mempool_free(req, &drbd_request_mempool); } static void wake_all_senders(struct drbd_connection *connection) diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h index cb97b3b30962..94c654020f0f 100644 --- a/drivers/block/drbd/drbd_req.h +++ b/drivers/block/drbd/drbd_req.h @@ -269,7 +269,7 @@ enum drbd_req_state_bits { static inline void drbd_req_make_private_bio(struct drbd_request *req, struct bio *bio_src) { struct bio *bio; - bio = bio_clone_fast(bio_src, GFP_NOIO, drbd_io_bio_set); + bio = bio_clone_fast(bio_src, GFP_NOIO, &drbd_io_bio_set); req->private_bio = bio; diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 8ec7235fc93b..8871b5044d9e 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -4450,7 +4450,7 @@ static ssize_t floppy_cmos_show(struct device *dev, return sprintf(buf, "%X\n", UDP->cmos); } -static DEVICE_ATTR(cmos, S_IRUGO, floppy_cmos_show, NULL); +static DEVICE_ATTR(cmos, 0444, floppy_cmos_show, NULL); static struct attribute *floppy_dev_attrs[] = { &dev_attr_cmos.attr, diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 5d4e31655d96..4838b0dbaad3 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -732,7 +732,7 @@ static ssize_t loop_attr_do_show_##_name(struct device *d, \ return loop_attr_show(d, b, loop_attr_##_name##_show); \ } \ static struct device_attribute loop_attr_##_name = \ - __ATTR(_name, S_IRUGO, loop_attr_do_show_##_name, NULL); + __ATTR(_name, 0444, loop_attr_do_show_##_name, NULL); static ssize_t loop_attr_backing_file_show(struct loop_device *lo, char *buf) { @@ -809,16 +809,17 @@ static struct attribute_group loop_attribute_group = { .attrs= loop_attrs, }; -static int loop_sysfs_init(struct loop_device *lo) +static void loop_sysfs_init(struct loop_device *lo) { - return sysfs_create_group(&disk_to_dev(lo->lo_disk)->kobj, - &loop_attribute_group); + lo->sysfs_inited = !sysfs_create_group(&disk_to_dev(lo->lo_disk)->kobj, + &loop_attribute_group); } static void loop_sysfs_exit(struct loop_device *lo) { - sysfs_remove_group(&disk_to_dev(lo->lo_disk)->kobj, - &loop_attribute_group); + if (lo->sysfs_inited) + sysfs_remove_group(&disk_to_dev(lo->lo_disk)->kobj, + &loop_attribute_group); } static void loop_config_discard(struct loop_device *lo) @@ -1068,6 +1069,7 @@ static int loop_clr_fd(struct loop_device *lo) if (bdev) { bdput(bdev); invalidate_bdev(bdev); + bdev->bd_inode->i_mapping->wb_err = 0; } set_capacity(lo->lo_disk, 0); loop_sysfs_exit(lo); @@ -1676,9 +1678,9 @@ static const struct block_device_operations lo_fops = { * And now the modules code and kernel interface. */ static int max_loop; -module_param(max_loop, int, S_IRUGO); +module_param(max_loop, int, 0444); MODULE_PARM_DESC(max_loop, "Maximum number of loop devices"); -module_param(max_part, int, S_IRUGO); +module_param(max_part, int, 0444); MODULE_PARM_DESC(max_part, "Maximum number of partitions per loop device"); MODULE_LICENSE("GPL"); MODULE_ALIAS_BLOCKDEV_MAJOR(LOOP_MAJOR); diff --git a/drivers/block/loop.h b/drivers/block/loop.h index b78de9879f4f..4d42c7af7de7 100644 --- a/drivers/block/loop.h +++ b/drivers/block/loop.h @@ -58,6 +58,7 @@ struct loop_device { struct kthread_worker worker; struct task_struct *worker_task; bool use_dio; + bool sysfs_inited; struct request_queue *lo_queue; struct blk_mq_tag_set tag_set; diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index 769c551e3d71..c73626decb46 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -2285,7 +2285,7 @@ static ssize_t mtip_hw_show_status(struct device *dev, return size; } -static DEVICE_ATTR(status, S_IRUGO, mtip_hw_show_status, NULL); +static DEVICE_ATTR(status, 0444, mtip_hw_show_status, NULL); /* debugsfs entries */ @@ -2566,10 +2566,9 @@ static int mtip_hw_debugfs_init(struct driver_data *dd) return -1; } - debugfs_create_file("flags", S_IRUGO, dd->dfs_node, dd, - &mtip_flags_fops); - debugfs_create_file("registers", S_IRUGO, dd->dfs_node, dd, - &mtip_regs_fops); + debugfs_create_file("flags", 0444, dd->dfs_node, dd, &mtip_flags_fops); + debugfs_create_file("registers", 0444, dd->dfs_node, dd, + &mtip_regs_fops); return 0; } @@ -2726,15 +2725,11 @@ static void mtip_softirq_done_fn(struct request *rq) blk_mq_end_request(rq, cmd->status); } -static void mtip_abort_cmd(struct request *req, void *data, - bool reserved) +static void mtip_abort_cmd(struct request *req, void *data, bool reserved) { struct mtip_cmd *cmd = blk_mq_rq_to_pdu(req); struct driver_data *dd = data; - if (!blk_mq_request_started(req)) - return; - dbg_printk(MTIP_DRV_NAME " Aborting request, tag = %d\n", req->tag); clear_bit(req->tag, dd->port->cmds_to_issue); @@ -2742,14 +2737,10 @@ static void mtip_abort_cmd(struct request *req, void *data, mtip_softirq_done_fn(req); } -static void mtip_queue_cmd(struct request *req, void *data, - bool reserved) +static void mtip_queue_cmd(struct request *req, void *data, bool reserved) { struct driver_data *dd = data; - if (!blk_mq_request_started(req)) - return; - set_bit(req->tag, dd->port->cmds_to_issue); blk_abort_request(req); } @@ -3720,7 +3711,8 @@ static enum blk_eh_timer_return mtip_cmd_timeout(struct request *req, struct mtip_cmd *cmd = blk_mq_rq_to_pdu(req); cmd->status = BLK_STS_TIMEOUT; - return BLK_EH_HANDLED; + blk_mq_complete_request(req); + return BLK_EH_DONE; } if (test_bit(req->tag, dd->port->cmds_to_issue)) @@ -3862,7 +3854,6 @@ skip_create_disk: blk_queue_max_hw_sectors(dd->queue, 0xffff); blk_queue_max_segment_size(dd->queue, 0x400000); blk_queue_io_min(dd->queue, 4096); - blk_queue_bounce_limit(dd->queue, dd->pdev->dma_mask); /* Signal trim support */ if (dd->trim_supp == true) { @@ -4273,7 +4264,7 @@ static int mtip_pci_probe(struct pci_dev *pdev, if (!dd->isr_workq) { dev_warn(&pdev->dev, "Can't create wq %d\n", dd->instance); rv = -ENOMEM; - goto block_initialize_err; + goto setmask_err; } memset(cpu_list, 0, sizeof(cpu_list)); @@ -4614,7 +4605,7 @@ static int __init mtip_init(void) } if (dfs_parent) { dfs_device_status = debugfs_create_file("device_status", - S_IRUGO, dfs_parent, NULL, + 0444, dfs_parent, NULL, &mtip_device_status_fops); if (IS_ERR_OR_NULL(dfs_device_status)) { pr_err("Error creating device_status node\n"); diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index afbc202ca6fd..3ed1ef8ee528 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -166,16 +166,19 @@ static ssize_t pid_show(struct device *dev, } static const struct device_attribute pid_attr = { - .attr = { .name = "pid", .mode = S_IRUGO}, + .attr = { .name = "pid", .mode = 0444}, .show = pid_show, }; static void nbd_dev_remove(struct nbd_device *nbd) { struct gendisk *disk = nbd->disk; + struct request_queue *q; + if (disk) { + q = disk->queue; del_gendisk(disk); - blk_cleanup_queue(disk->queue); + blk_cleanup_queue(q); blk_mq_free_tag_set(&nbd->tag_set); disk->private_data = NULL; put_disk(disk); @@ -213,7 +216,15 @@ static void nbd_mark_nsock_dead(struct nbd_device *nbd, struct nbd_sock *nsock, } if (!nsock->dead) { kernel_sock_shutdown(nsock->sock, SHUT_RDWR); - atomic_dec(&nbd->config->live_connections); + if (atomic_dec_return(&nbd->config->live_connections) == 0) { + if (test_and_clear_bit(NBD_DISCONNECT_REQUESTED, + &nbd->config->runtime_flags)) { + set_bit(NBD_DISCONNECTED, + &nbd->config->runtime_flags); + dev_info(nbd_to_dev(nbd), + "Disconnected due to user request.\n"); + } + } } nsock->dead = true; nsock->pending = NULL; @@ -231,9 +242,22 @@ static void nbd_size_clear(struct nbd_device *nbd) static void nbd_size_update(struct nbd_device *nbd) { struct nbd_config *config = nbd->config; + struct block_device *bdev = bdget_disk(nbd->disk, 0); + + if (config->flags & NBD_FLAG_SEND_TRIM) { + nbd->disk->queue->limits.discard_granularity = config->blksize; + blk_queue_max_discard_sectors(nbd->disk->queue, UINT_MAX); + } blk_queue_logical_block_size(nbd->disk->queue, config->blksize); blk_queue_physical_block_size(nbd->disk->queue, config->blksize); set_capacity(nbd->disk, config->bytesize >> 9); + if (bdev) { + if (bdev->bd_disk) + bd_set_size(bdev, config->bytesize); + else + bdev->bd_invalidated = 1; + bdput(bdev); + } kobject_uevent(&nbd_to_dev(nbd)->kobj, KOBJ_CHANGE); } @@ -243,6 +267,8 @@ static void nbd_size_set(struct nbd_device *nbd, loff_t blocksize, struct nbd_config *config = nbd->config; config->blksize = blocksize; config->bytesize = blocksize * nr_blocks; + if (nbd->task_recv != NULL) + nbd_size_update(nbd); } static void nbd_complete_rq(struct request *req) @@ -286,13 +312,15 @@ static enum blk_eh_timer_return nbd_xmit_timeout(struct request *req, if (!refcount_inc_not_zero(&nbd->config_refs)) { cmd->status = BLK_STS_TIMEOUT; - return BLK_EH_HANDLED; + goto done; } config = nbd->config; if (config->num_connections > 1) { dev_err_ratelimited(nbd_to_dev(nbd), - "Connection timed out, retrying\n"); + "Connection timed out, retrying (%d/%d alive)\n", + atomic_read(&config->live_connections), + config->num_connections); /* * Hooray we have more connections, requeue this IO, the submit * path will put it on a real connection. @@ -314,7 +342,7 @@ static enum blk_eh_timer_return nbd_xmit_timeout(struct request *req, } blk_mq_requeue_request(req, true); nbd_config_put(nbd); - return BLK_EH_NOT_HANDLED; + return BLK_EH_DONE; } } else { dev_err_ratelimited(nbd_to_dev(nbd), @@ -324,8 +352,9 @@ static enum blk_eh_timer_return nbd_xmit_timeout(struct request *req, cmd->status = BLK_STS_IOERR; sock_shutdown(nbd); nbd_config_put(nbd); - - return BLK_EH_HANDLED; +done: + blk_mq_complete_request(req); + return BLK_EH_DONE; } /* @@ -647,11 +676,8 @@ static void recv_work(struct work_struct *work) static void nbd_clear_req(struct request *req, void *data, bool reserved) { - struct nbd_cmd *cmd; + struct nbd_cmd *cmd = blk_mq_rq_to_pdu(req); - if (!blk_mq_request_started(req)) - return; - cmd = blk_mq_rq_to_pdu(req); cmd->status = BLK_STS_IOERR; blk_mq_complete_request(req); } @@ -714,10 +740,9 @@ static int wait_for_reconnect(struct nbd_device *nbd) return 0; if (test_bit(NBD_DISCONNECTED, &config->runtime_flags)) return 0; - wait_event_timeout(config->conn_wait, - atomic_read(&config->live_connections), - config->dead_conn_timeout); - return atomic_read(&config->live_connections); + return wait_event_timeout(config->conn_wait, + atomic_read(&config->live_connections) > 0, + config->dead_conn_timeout) > 0; } static int nbd_handle_cmd(struct nbd_cmd *cmd, int index) @@ -950,10 +975,6 @@ static void nbd_bdev_reset(struct block_device *bdev) if (bdev->bd_openers > 1) return; bd_set_size(bdev, 0); - if (max_part > 0) { - blkdev_reread_part(bdev); - bdev->bd_invalidated = 1; - } } static void nbd_parse_flags(struct nbd_device *nbd) @@ -1040,6 +1061,8 @@ static void nbd_config_put(struct nbd_device *nbd) nbd->config = NULL; nbd->tag_set.timeout = 0; + nbd->disk->queue->limits.discard_granularity = 0; + blk_queue_max_discard_sectors(nbd->disk->queue, UINT_MAX); blk_queue_flag_clear(QUEUE_FLAG_DISCARD, nbd->disk->queue); mutex_unlock(&nbd->config_lock); @@ -1109,7 +1132,6 @@ static int nbd_start_device_ioctl(struct nbd_device *nbd, struct block_device *b if (ret) return ret; - bd_set_size(bdev, config->bytesize); if (max_part) bdev->bd_invalidated = 1; mutex_unlock(&nbd->config_lock); @@ -1118,7 +1140,7 @@ static int nbd_start_device_ioctl(struct nbd_device *nbd, struct block_device *b if (ret) sock_shutdown(nbd); mutex_lock(&nbd->config_lock); - bd_set_size(bdev, 0); + nbd_bdev_reset(bdev); /* user requested, ignore socket errors */ if (test_bit(NBD_DISCONNECT_REQUESTED, &config->runtime_flags)) ret = 0; @@ -1269,6 +1291,9 @@ static int nbd_open(struct block_device *bdev, fmode_t mode) refcount_set(&nbd->config_refs, 1); refcount_inc(&nbd->refs); mutex_unlock(&nbd->config_lock); + bdev->bd_invalidated = 1; + } else if (nbd_disconnected(nbd->config)) { + bdev->bd_invalidated = 1; } out: mutex_unlock(&nbd_index_mutex); @@ -1490,8 +1515,8 @@ static int nbd_dev_add(int index) */ blk_queue_flag_set(QUEUE_FLAG_NONROT, disk->queue); blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, disk->queue); - disk->queue->limits.discard_granularity = 512; - blk_queue_max_discard_sectors(disk->queue, UINT_MAX); + disk->queue->limits.discard_granularity = 0; + blk_queue_max_discard_sectors(disk->queue, 0); blk_queue_max_segment_size(disk->queue, UINT_MAX); blk_queue_max_segments(disk->queue, USHRT_MAX); blk_queue_max_hw_sectors(disk->queue, 65536); @@ -1755,6 +1780,7 @@ static int nbd_genl_disconnect(struct sk_buff *skb, struct genl_info *info) } mutex_lock(&nbd->config_lock); nbd_disconnect(nbd); + nbd_clear_sock(nbd); mutex_unlock(&nbd->config_lock); if (test_and_clear_bit(NBD_HAS_CONFIG_REF, &nbd->config->runtime_flags)) @@ -2093,7 +2119,8 @@ static int __init nbd_init(void) if (nbds_max > 1UL << (MINORBITS - part_shift)) return -EINVAL; recv_workqueue = alloc_workqueue("knbd-recv", - WQ_MEM_RECLAIM | WQ_HIGHPRI, 0); + WQ_MEM_RECLAIM | WQ_HIGHPRI | + WQ_UNBOUND, 0); if (!recv_workqueue) return -ENOMEM; diff --git a/drivers/block/null_blk.c b/drivers/block/null_blk.c index a76553293a31..2bdadd7f1454 100644 --- a/drivers/block/null_blk.c +++ b/drivers/block/null_blk.c @@ -157,23 +157,23 @@ enum { }; static int g_no_sched; -module_param_named(no_sched, g_no_sched, int, S_IRUGO); +module_param_named(no_sched, g_no_sched, int, 0444); MODULE_PARM_DESC(no_sched, "No io scheduler"); static int g_submit_queues = 1; -module_param_named(submit_queues, g_submit_queues, int, S_IRUGO); +module_param_named(submit_queues, g_submit_queues, int, 0444); MODULE_PARM_DESC(submit_queues, "Number of submission queues"); static int g_home_node = NUMA_NO_NODE; -module_param_named(home_node, g_home_node, int, S_IRUGO); +module_param_named(home_node, g_home_node, int, 0444); MODULE_PARM_DESC(home_node, "Home node for the device"); #ifdef CONFIG_BLK_DEV_NULL_BLK_FAULT_INJECTION static char g_timeout_str[80]; -module_param_string(timeout, g_timeout_str, sizeof(g_timeout_str), S_IRUGO); +module_param_string(timeout, g_timeout_str, sizeof(g_timeout_str), 0444); static char g_requeue_str[80]; -module_param_string(requeue, g_requeue_str, sizeof(g_requeue_str), S_IRUGO); +module_param_string(requeue, g_requeue_str, sizeof(g_requeue_str), 0444); #endif static int g_queue_mode = NULL_Q_MQ; @@ -203,27 +203,27 @@ static const struct kernel_param_ops null_queue_mode_param_ops = { .get = param_get_int, }; -device_param_cb(queue_mode, &null_queue_mode_param_ops, &g_queue_mode, S_IRUGO); +device_param_cb(queue_mode, &null_queue_mode_param_ops, &g_queue_mode, 0444); MODULE_PARM_DESC(queue_mode, "Block interface to use (0=bio,1=rq,2=multiqueue)"); static int g_gb = 250; -module_param_named(gb, g_gb, int, S_IRUGO); +module_param_named(gb, g_gb, int, 0444); MODULE_PARM_DESC(gb, "Size in GB"); static int g_bs = 512; -module_param_named(bs, g_bs, int, S_IRUGO); +module_param_named(bs, g_bs, int, 0444); MODULE_PARM_DESC(bs, "Block size (in bytes)"); static int nr_devices = 1; -module_param(nr_devices, int, S_IRUGO); +module_param(nr_devices, int, 0444); MODULE_PARM_DESC(nr_devices, "Number of devices to register"); static bool g_blocking; -module_param_named(blocking, g_blocking, bool, S_IRUGO); +module_param_named(blocking, g_blocking, bool, 0444); MODULE_PARM_DESC(blocking, "Register as a blocking blk-mq driver device"); static bool shared_tags; -module_param(shared_tags, bool, S_IRUGO); +module_param(shared_tags, bool, 0444); MODULE_PARM_DESC(shared_tags, "Share tag set between devices for blk-mq"); static int g_irqmode = NULL_IRQ_SOFTIRQ; @@ -239,19 +239,19 @@ static const struct kernel_param_ops null_irqmode_param_ops = { .get = param_get_int, }; -device_param_cb(irqmode, &null_irqmode_param_ops, &g_irqmode, S_IRUGO); +device_param_cb(irqmode, &null_irqmode_param_ops, &g_irqmode, 0444); MODULE_PARM_DESC(irqmode, "IRQ completion handler. 0-none, 1-softirq, 2-timer"); static unsigned long g_completion_nsec = 10000; -module_param_named(completion_nsec, g_completion_nsec, ulong, S_IRUGO); +module_param_named(completion_nsec, g_completion_nsec, ulong, 0444); MODULE_PARM_DESC(completion_nsec, "Time in ns to complete a request in hardware. Default: 10,000ns"); static int g_hw_queue_depth = 64; -module_param_named(hw_queue_depth, g_hw_queue_depth, int, S_IRUGO); +module_param_named(hw_queue_depth, g_hw_queue_depth, int, 0444); MODULE_PARM_DESC(hw_queue_depth, "Queue depth for each hardware queue. Default: 64"); static bool g_use_per_node_hctx; -module_param_named(use_per_node_hctx, g_use_per_node_hctx, bool, S_IRUGO); +module_param_named(use_per_node_hctx, g_use_per_node_hctx, bool, 0444); MODULE_PARM_DESC(use_per_node_hctx, "Use per-node allocation for hardware context queues. Default: false"); static struct nullb_device *null_alloc_dev(void); @@ -1365,7 +1365,8 @@ static blk_qc_t null_queue_bio(struct request_queue *q, struct bio *bio) static enum blk_eh_timer_return null_rq_timed_out_fn(struct request *rq) { pr_info("null: rq %p timed out\n", rq); - return BLK_EH_HANDLED; + blk_mq_complete_request(rq); + return BLK_EH_DONE; } static int null_rq_prep_fn(struct request_queue *q, struct request *req) @@ -1427,7 +1428,8 @@ static void null_request_fn(struct request_queue *q) static enum blk_eh_timer_return null_timeout_rq(struct request *rq, bool res) { pr_info("null: rq %p timed out\n", rq); - return BLK_EH_HANDLED; + blk_mq_complete_request(rq); + return BLK_EH_DONE; } static blk_status_t null_queue_rq(struct blk_mq_hw_ctx *hctx, diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index 27a44b97393a..8961b190e256 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -740,7 +740,7 @@ static int pd_special_command(struct pd_unit *disk, { struct request *rq; - rq = blk_get_request(disk->gd->queue, REQ_OP_DRV_IN, __GFP_RECLAIM); + rq = blk_get_request(disk->gd->queue, REQ_OP_DRV_IN, 0); if (IS_ERR(rq)) return PTR_ERR(rq); diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index c61d20c9f3f8..b3f83cd96f33 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -97,8 +97,8 @@ static int pktdev_major; static int write_congestion_on = PKT_WRITE_CONGESTION_ON; static int write_congestion_off = PKT_WRITE_CONGESTION_OFF; static struct mutex ctl_mutex; /* Serialize open/close/setup/teardown */ -static mempool_t *psd_pool; -static struct bio_set *pkt_bio_set; +static mempool_t psd_pool; +static struct bio_set pkt_bio_set; static struct class *class_pktcdvd = NULL; /* /sys/class/pktcdvd */ static struct dentry *pkt_debugfs_root = NULL; /* /sys/kernel/debug/pktcdvd */ @@ -478,8 +478,8 @@ static void pkt_debugfs_dev_new(struct pktcdvd_device *pd) if (!pd->dfs_d_root) return; - pd->dfs_f_info = debugfs_create_file("info", S_IRUGO, - pd->dfs_d_root, pd, &debug_fops); + pd->dfs_f_info = debugfs_create_file("info", 0444, + pd->dfs_d_root, pd, &debug_fops); } static void pkt_debugfs_dev_remove(struct pktcdvd_device *pd) @@ -631,7 +631,7 @@ static inline struct pkt_rb_node *pkt_rbtree_next(struct pkt_rb_node *node) static void pkt_rbtree_erase(struct pktcdvd_device *pd, struct pkt_rb_node *node) { rb_erase(&node->rb_node, &pd->bio_queue); - mempool_free(node, pd->rb_pool); + mempool_free(node, &pd->rb_pool); pd->bio_queue_size--; BUG_ON(pd->bio_queue_size < 0); } @@ -704,13 +704,13 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command * int ret = 0; rq = blk_get_request(q, (cgc->data_direction == CGC_DATA_WRITE) ? - REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, __GFP_RECLAIM); + REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, 0); if (IS_ERR(rq)) return PTR_ERR(rq); if (cgc->buflen) { ret = blk_rq_map_kern(q, rq, cgc->buffer, cgc->buflen, - __GFP_RECLAIM); + GFP_NOIO); if (ret) goto out; } @@ -1285,7 +1285,7 @@ static void pkt_start_write(struct pktcdvd_device *pd, struct packet_data *pkt) * Fill-in bvec with data from orig_bios. */ spin_lock(&pkt->lock); - bio_copy_data(pkt->w_bio, pkt->orig_bios.head); + bio_list_copy_data(pkt->w_bio, pkt->orig_bios.head); pkt_set_state(pkt, PACKET_WRITE_WAIT_STATE); spin_unlock(&pkt->lock); @@ -2303,14 +2303,14 @@ static void pkt_end_io_read_cloned(struct bio *bio) psd->bio->bi_status = bio->bi_status; bio_put(bio); bio_endio(psd->bio); - mempool_free(psd, psd_pool); + mempool_free(psd, &psd_pool); pkt_bio_finished(pd); } static void pkt_make_request_read(struct pktcdvd_device *pd, struct bio *bio) { - struct bio *cloned_bio = bio_clone_fast(bio, GFP_NOIO, pkt_bio_set); - struct packet_stacked_data *psd = mempool_alloc(psd_pool, GFP_NOIO); + struct bio *cloned_bio = bio_clone_fast(bio, GFP_NOIO, &pkt_bio_set); + struct packet_stacked_data *psd = mempool_alloc(&psd_pool, GFP_NOIO); psd->pd = pd; psd->bio = bio; @@ -2381,7 +2381,7 @@ static void pkt_make_request_write(struct request_queue *q, struct bio *bio) /* * No matching packet found. Store the bio in the work queue. */ - node = mempool_alloc(pd->rb_pool, GFP_NOIO); + node = mempool_alloc(&pd->rb_pool, GFP_NOIO); node->bio = bio; spin_lock(&pd->lock); BUG_ON(pd->bio_queue_size < 0); @@ -2451,7 +2451,7 @@ static blk_qc_t pkt_make_request(struct request_queue *q, struct bio *bio) split = bio_split(bio, last_zone - bio->bi_iter.bi_sector, - GFP_NOIO, pkt_bio_set); + GFP_NOIO, &pkt_bio_set); bio_chain(split, bio); } else { split = bio; @@ -2538,18 +2538,6 @@ static int pkt_seq_show(struct seq_file *m, void *p) return 0; } -static int pkt_seq_open(struct inode *inode, struct file *file) -{ - return single_open(file, pkt_seq_show, PDE_DATA(inode)); -} - -static const struct file_operations pkt_proc_fops = { - .open = pkt_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release -}; - static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev) { int i; @@ -2604,7 +2592,7 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev) goto out_mem; } - proc_create_data(pd->name, 0, pkt_proc, &pkt_proc_fops, pd); + proc_create_single_data(pd->name, 0, pkt_proc, pkt_seq_show, pd); pkt_dbg(1, pd, "writer mapped to %s\n", bdevname(bdev, b)); return 0; @@ -2707,9 +2695,9 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev) if (!pd) goto out_mutex; - pd->rb_pool = mempool_create_kmalloc_pool(PKT_RB_POOL_SIZE, - sizeof(struct pkt_rb_node)); - if (!pd->rb_pool) + ret = mempool_init_kmalloc_pool(&pd->rb_pool, PKT_RB_POOL_SIZE, + sizeof(struct pkt_rb_node)); + if (ret) goto out_mem; INIT_LIST_HEAD(&pd->cdrw.pkt_free_list); @@ -2766,7 +2754,7 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev) out_mem2: put_disk(disk); out_mem: - mempool_destroy(pd->rb_pool); + mempool_exit(&pd->rb_pool); kfree(pd); out_mutex: mutex_unlock(&ctl_mutex); @@ -2817,7 +2805,7 @@ static int pkt_remove_dev(dev_t pkt_dev) blk_cleanup_queue(pd->disk->queue); put_disk(pd->disk); - mempool_destroy(pd->rb_pool); + mempool_exit(&pd->rb_pool); kfree(pd); /* This is safe: open() is still holding a reference. */ @@ -2914,14 +2902,14 @@ static int __init pkt_init(void) mutex_init(&ctl_mutex); - psd_pool = mempool_create_kmalloc_pool(PSD_POOL_SIZE, - sizeof(struct packet_stacked_data)); - if (!psd_pool) - return -ENOMEM; - pkt_bio_set = bioset_create(BIO_POOL_SIZE, 0, 0); - if (!pkt_bio_set) { - mempool_destroy(psd_pool); - return -ENOMEM; + ret = mempool_init_kmalloc_pool(&psd_pool, PSD_POOL_SIZE, + sizeof(struct packet_stacked_data)); + if (ret) + return ret; + ret = bioset_init(&pkt_bio_set, BIO_POOL_SIZE, 0, 0); + if (ret) { + mempool_exit(&psd_pool); + return ret; } ret = register_blkdev(pktdev_major, DRIVER_NAME); @@ -2954,8 +2942,8 @@ out_misc: out: unregister_blkdev(pktdev_major, DRIVER_NAME); out2: - mempool_destroy(psd_pool); - bioset_free(pkt_bio_set); + mempool_exit(&psd_pool); + bioset_exit(&pkt_bio_set); return ret; } @@ -2968,8 +2956,8 @@ static void __exit pkt_exit(void) pkt_sysfs_cleanup(); unregister_blkdev(pktdev_major, DRIVER_NAME); - mempool_destroy(psd_pool); - bioset_free(pkt_bio_set); + mempool_exit(&psd_pool); + bioset_exit(&pkt_bio_set); } MODULE_DESCRIPTION("Packet writing layer for CD/DVD drives"); diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c index 075662f2cf46..afe1508d82c6 100644 --- a/drivers/block/ps3disk.c +++ b/drivers/block/ps3disk.c @@ -465,8 +465,6 @@ static int ps3disk_probe(struct ps3_system_bus_device *_dev) priv->queue = queue; queue->queuedata = dev; - blk_queue_bounce_limit(queue, BLK_BOUNCE_HIGH); - blk_queue_max_hw_sectors(queue, dev->bounce_size >> 9); blk_queue_segment_boundary(queue, -1UL); blk_queue_dma_alignment(queue, dev->blk_size-1); diff --git a/drivers/block/ps3vram.c b/drivers/block/ps3vram.c index 6a55959cbf78..8fa4533a1249 100644 --- a/drivers/block/ps3vram.c +++ b/drivers/block/ps3vram.c @@ -521,26 +521,13 @@ static int ps3vram_proc_show(struct seq_file *m, void *v) return 0; } -static int ps3vram_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, ps3vram_proc_show, PDE_DATA(inode)); -} - -static const struct file_operations ps3vram_proc_fops = { - .owner = THIS_MODULE, - .open = ps3vram_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static void ps3vram_proc_init(struct ps3_system_bus_device *dev) { struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); struct proc_dir_entry *pde; - pde = proc_create_data(DEVICE_NAME, 0444, NULL, &ps3vram_proc_fops, - priv); + pde = proc_create_single_data(DEVICE_NAME, 0444, NULL, + ps3vram_proc_show, priv); if (!pde) dev_warn(&dev->core, "failed to create /proc entry\n"); } diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 33b36fea1d73..af354047ac4b 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -424,7 +424,7 @@ static struct workqueue_struct *rbd_wq; * single-major requires >= 0.75 version of userspace rbd utility. */ static bool single_major = true; -module_param(single_major, bool, S_IRUGO); +module_param(single_major, bool, 0444); MODULE_PARM_DESC(single_major, "Use a single major number for all rbd devices (default: true)"); static ssize_t rbd_add(struct bus_type *bus, const char *buf, @@ -468,11 +468,11 @@ static ssize_t rbd_supported_features_show(struct bus_type *bus, char *buf) return sprintf(buf, "0x%llx\n", RBD_FEATURES_SUPPORTED); } -static BUS_ATTR(add, S_IWUSR, NULL, rbd_add); -static BUS_ATTR(remove, S_IWUSR, NULL, rbd_remove); -static BUS_ATTR(add_single_major, S_IWUSR, NULL, rbd_add_single_major); -static BUS_ATTR(remove_single_major, S_IWUSR, NULL, rbd_remove_single_major); -static BUS_ATTR(supported_features, S_IRUGO, rbd_supported_features_show, NULL); +static BUS_ATTR(add, 0200, NULL, rbd_add); +static BUS_ATTR(remove, 0200, NULL, rbd_remove); +static BUS_ATTR(add_single_major, 0200, NULL, rbd_add_single_major); +static BUS_ATTR(remove_single_major, 0200, NULL, rbd_remove_single_major); +static BUS_ATTR(supported_features, 0444, rbd_supported_features_show, NULL); static struct attribute *rbd_bus_attrs[] = { &bus_attr_add.attr, @@ -4204,22 +4204,22 @@ static ssize_t rbd_image_refresh(struct device *dev, return size; } -static DEVICE_ATTR(size, S_IRUGO, rbd_size_show, NULL); -static DEVICE_ATTR(features, S_IRUGO, rbd_features_show, NULL); -static DEVICE_ATTR(major, S_IRUGO, rbd_major_show, NULL); -static DEVICE_ATTR(minor, S_IRUGO, rbd_minor_show, NULL); -static DEVICE_ATTR(client_addr, S_IRUGO, rbd_client_addr_show, NULL); -static DEVICE_ATTR(client_id, S_IRUGO, rbd_client_id_show, NULL); -static DEVICE_ATTR(cluster_fsid, S_IRUGO, rbd_cluster_fsid_show, NULL); -static DEVICE_ATTR(config_info, S_IRUSR, rbd_config_info_show, NULL); -static DEVICE_ATTR(pool, S_IRUGO, rbd_pool_show, NULL); -static DEVICE_ATTR(pool_id, S_IRUGO, rbd_pool_id_show, NULL); -static DEVICE_ATTR(name, S_IRUGO, rbd_name_show, NULL); -static DEVICE_ATTR(image_id, S_IRUGO, rbd_image_id_show, NULL); -static DEVICE_ATTR(refresh, S_IWUSR, NULL, rbd_image_refresh); -static DEVICE_ATTR(current_snap, S_IRUGO, rbd_snap_show, NULL); -static DEVICE_ATTR(snap_id, S_IRUGO, rbd_snap_id_show, NULL); -static DEVICE_ATTR(parent, S_IRUGO, rbd_parent_show, NULL); +static DEVICE_ATTR(size, 0444, rbd_size_show, NULL); +static DEVICE_ATTR(features, 0444, rbd_features_show, NULL); +static DEVICE_ATTR(major, 0444, rbd_major_show, NULL); +static DEVICE_ATTR(minor, 0444, rbd_minor_show, NULL); +static DEVICE_ATTR(client_addr, 0444, rbd_client_addr_show, NULL); +static DEVICE_ATTR(client_id, 0444, rbd_client_id_show, NULL); +static DEVICE_ATTR(cluster_fsid, 0444, rbd_cluster_fsid_show, NULL); +static DEVICE_ATTR(config_info, 0400, rbd_config_info_show, NULL); +static DEVICE_ATTR(pool, 0444, rbd_pool_show, NULL); +static DEVICE_ATTR(pool_id, 0444, rbd_pool_id_show, NULL); +static DEVICE_ATTR(name, 0444, rbd_name_show, NULL); +static DEVICE_ATTR(image_id, 0444, rbd_image_id_show, NULL); +static DEVICE_ATTR(refresh, 0200, NULL, rbd_image_refresh); +static DEVICE_ATTR(current_snap, 0444, rbd_snap_show, NULL); +static DEVICE_ATTR(snap_id, 0444, rbd_snap_id_show, NULL); +static DEVICE_ATTR(parent, 0444, rbd_parent_show, NULL); static struct attribute *rbd_attrs[] = { &dev_attr_size.attr, diff --git a/drivers/block/rsxx/core.c b/drivers/block/rsxx/core.c index 34997df132e2..09537bee387f 100644 --- a/drivers/block/rsxx/core.c +++ b/drivers/block/rsxx/core.c @@ -247,19 +247,19 @@ static void rsxx_debugfs_dev_new(struct rsxx_cardinfo *card) if (IS_ERR_OR_NULL(card->debugfs_dir)) goto failed_debugfs_dir; - debugfs_stats = debugfs_create_file("stats", S_IRUGO, + debugfs_stats = debugfs_create_file("stats", 0444, card->debugfs_dir, card, &debugfs_stats_fops); if (IS_ERR_OR_NULL(debugfs_stats)) goto failed_debugfs_stats; - debugfs_pci_regs = debugfs_create_file("pci_regs", S_IRUGO, + debugfs_pci_regs = debugfs_create_file("pci_regs", 0444, card->debugfs_dir, card, &debugfs_pci_regs_fops); if (IS_ERR_OR_NULL(debugfs_pci_regs)) goto failed_debugfs_pci_regs; - debugfs_cram = debugfs_create_file("cram", S_IRUGO | S_IWUSR, + debugfs_cram = debugfs_create_file("cram", 0644, card->debugfs_dir, card, &debugfs_cram_fops); if (IS_ERR_OR_NULL(debugfs_cram)) diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c index 08586dc14e85..4d90e5eba2f5 100644 --- a/drivers/block/sx8.c +++ b/drivers/block/sx8.c @@ -567,7 +567,7 @@ static struct carm_request *carm_get_special(struct carm_host *host) if (!crq) return NULL; - rq = blk_get_request(host->oob_q, REQ_OP_DRV_OUT, GFP_KERNEL); + rq = blk_get_request(host->oob_q, REQ_OP_DRV_OUT, 0); if (IS_ERR(rq)) { spin_lock_irqsave(&host->lock, flags); carm_put_request(host, crq); diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 4a07593c2efd..23752dc99b00 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -298,7 +298,7 @@ static int virtblk_get_id(struct gendisk *disk, char *id_str) struct request *req; int err; - req = blk_get_request(q, REQ_OP_DRV_IN, GFP_KERNEL); + req = blk_get_request(q, REQ_OP_DRV_IN, 0); if (IS_ERR(req)) return PTR_ERR(req); @@ -371,7 +371,7 @@ static ssize_t virtblk_serial_show(struct device *dev, return err; } -static DEVICE_ATTR(serial, S_IRUGO, virtblk_serial_show, NULL); +static DEVICE_ATTR(serial, 0444, virtblk_serial_show, NULL); /* The queue's logical block size must be set before calling this */ static void virtblk_update_capacity(struct virtio_blk *vblk, bool resize) @@ -576,10 +576,10 @@ virtblk_cache_type_show(struct device *dev, struct device_attribute *attr, } static const struct device_attribute dev_attr_cache_type_ro = - __ATTR(cache_type, S_IRUGO, + __ATTR(cache_type, 0444, virtblk_cache_type_show, NULL); static const struct device_attribute dev_attr_cache_type_rw = - __ATTR(cache_type, S_IRUGO|S_IWUSR, + __ATTR(cache_type, 0644, virtblk_cache_type_show, virtblk_cache_type_store); static int virtblk_init_request(struct blk_mq_tag_set *set, struct request *rq, diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index 987d665e82de..b55b245e8052 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -98,7 +98,7 @@ MODULE_PARM_DESC(max_queues, * backend, 4KB page granularity is used. */ unsigned int xen_blkif_max_ring_order = XENBUS_MAX_RING_GRANT_ORDER; -module_param_named(max_ring_page_order, xen_blkif_max_ring_order, int, S_IRUGO); +module_param_named(max_ring_page_order, xen_blkif_max_ring_order, int, 0444); MODULE_PARM_DESC(max_ring_page_order, "Maximum order of pages to be used for the shared ring"); /* * The LRU mechanism to clean the lists of persistent grants needs to diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c index 21c1be1eb226..66412eededda 100644 --- a/drivers/block/xen-blkback/xenbus.c +++ b/drivers/block/xen-blkback/xenbus.c @@ -367,7 +367,7 @@ int __init xen_blkif_interface_init(void) out: \ return sprintf(buf, format, result); \ } \ - static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) + static DEVICE_ATTR(name, 0444, show_##name, NULL) VBD_SHOW_ALLRING(oo_req, "%llu\n"); VBD_SHOW_ALLRING(rd_req, "%llu\n"); @@ -403,7 +403,7 @@ static const struct attribute_group xen_vbdstat_group = { \ return sprintf(buf, format, ##args); \ } \ - static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) + static DEVICE_ATTR(name, 0444, show_##name, NULL) VBD_SHOW(physical_device, "%x:%x\n", be->major, be->minor); VBD_SHOW(mode, "%s\n", be->mode); diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 2a8e7813bd1a..ae00a82f350b 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -129,13 +129,12 @@ static const struct block_device_operations xlvbd_block_fops; */ static unsigned int xen_blkif_max_segments = 32; -module_param_named(max_indirect_segments, xen_blkif_max_segments, uint, - S_IRUGO); +module_param_named(max_indirect_segments, xen_blkif_max_segments, uint, 0444); MODULE_PARM_DESC(max_indirect_segments, "Maximum amount of segments in indirect requests (default is 32)"); static unsigned int xen_blkif_max_queues = 4; -module_param_named(max_queues, xen_blkif_max_queues, uint, S_IRUGO); +module_param_named(max_queues, xen_blkif_max_queues, uint, 0444); MODULE_PARM_DESC(max_queues, "Maximum number of hardware queues/rings used per virtual disk"); /* @@ -143,7 +142,7 @@ MODULE_PARM_DESC(max_queues, "Maximum number of hardware queues/rings used per v * backend, 4KB page granularity is used. */ static unsigned int xen_blkif_max_ring_order; -module_param_named(max_ring_page_order, xen_blkif_max_ring_order, int, S_IRUGO); +module_param_named(max_ring_page_order, xen_blkif_max_ring_order, int, 0444); MODULE_PARM_DESC(max_ring_page_order, "Maximum order of pages to be used for the shared ring"); #define BLK_RING_SIZE(info) \ diff --git a/drivers/bus/fsl-mc/fsl-mc-msi.c b/drivers/bus/fsl-mc/fsl-mc-msi.c index ec35e255b496..8b9c66d7c4ff 100644 --- a/drivers/bus/fsl-mc/fsl-mc-msi.c +++ b/drivers/bus/fsl-mc/fsl-mc-msi.c @@ -163,6 +163,8 @@ struct irq_domain *fsl_mc_msi_create_irq_domain(struct fwnode_handle *fwnode, { struct irq_domain *domain; + if (WARN_ON((info->flags & MSI_FLAG_LEVEL_CAPABLE))) + info->flags &= ~MSI_FLAG_LEVEL_CAPABLE; if (info->flags & MSI_FLAG_USE_DEF_DOM_OPS) fsl_mc_msi_update_dom_ops(info); if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS) diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index bfc566d3f31a..9adc8c3eb0fa 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -2192,7 +2192,7 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, len = nr * CD_FRAMESIZE_RAW; - rq = blk_get_request(q, REQ_OP_SCSI_IN, GFP_KERNEL); + rq = blk_get_request(q, REQ_OP_SCSI_IN, 0); if (IS_ERR(rq)) { ret = PTR_ERR(rq); break; diff --git a/drivers/char/apm-emulation.c b/drivers/char/apm-emulation.c index a5e2f9e557ea..53436c03dbce 100644 --- a/drivers/char/apm-emulation.c +++ b/drivers/char/apm-emulation.c @@ -461,19 +461,6 @@ static int proc_apm_show(struct seq_file *m, void *v) return 0; } - -static int proc_apm_open(struct inode *inode, struct file *file) -{ - return single_open(file, proc_apm_show, NULL); -} - -static const struct file_operations apm_proc_fops = { - .owner = THIS_MODULE, - .open = proc_apm_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; #endif static int kapmd(void *arg) @@ -657,7 +644,7 @@ static int __init apm_init(void) wake_up_process(kapmd_tsk); #ifdef CONFIG_PROC_FS - proc_create("apm", 0, NULL, &apm_proc_fops); + proc_create_single("apm", 0, NULL, proc_apm_show); #endif ret = misc_register(&apm_device); diff --git a/drivers/char/ds1620.c b/drivers/char/ds1620.c index eb53cbadb68f..a5ecf6dae02e 100644 --- a/drivers/char/ds1620.c +++ b/drivers/char/ds1620.c @@ -345,18 +345,6 @@ static int ds1620_proc_therm_show(struct seq_file *m, void *v) fan_state[netwinder_get_fan()]); return 0; } - -static int ds1620_proc_therm_open(struct inode *inode, struct file *file) -{ - return single_open(file, ds1620_proc_therm_show, NULL); -} - -static const struct file_operations ds1620_proc_therm_fops = { - .open = ds1620_proc_therm_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; #endif static const struct file_operations ds1620_fops = { @@ -404,7 +392,7 @@ static int __init ds1620_init(void) return ret; #ifdef THERM_USE_PROC - if (!proc_create("therm", 0, NULL, &ds1620_proc_therm_fops)) + if (!proc_create_single("therm", 0, NULL, ds1620_proc_therm_show)) printk(KERN_ERR "therm: unable to register /proc/therm\n"); #endif diff --git a/drivers/char/efirtc.c b/drivers/char/efirtc.c index dc62568b7dde..d9aab643997e 100644 --- a/drivers/char/efirtc.c +++ b/drivers/char/efirtc.c @@ -358,19 +358,6 @@ static int efi_rtc_proc_show(struct seq_file *m, void *v) return 0; } - -static int efi_rtc_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, efi_rtc_proc_show, NULL); -} - -static const struct file_operations efi_rtc_proc_fops = { - .open = efi_rtc_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static int __init efi_rtc_init(void) { @@ -386,7 +373,7 @@ efi_rtc_init(void) return ret; } - dir = proc_create("driver/efirtc", 0, NULL, &efi_rtc_proc_fops); + dir = proc_create_single("driver/efirtc", 0, NULL, efi_rtc_proc_show); if (dir == NULL) { printk(KERN_ERR "efirtc: can't create /proc/driver/efirtc.\n"); misc_deregister(&efi_rtc_dev); diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index d53541e96bee..c34b257d852d 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -347,6 +347,7 @@ config HW_RANDOM_STM32 tristate "STMicroelectronics STM32 random number generator" depends on HW_RANDOM && (ARCH_STM32 || COMPILE_TEST) depends on HAS_IOMEM + default HW_RANDOM help This driver provides kernel-side support for the Random Number Generator hardware found on STM32 microcontrollers. diff --git a/drivers/char/hw_random/n2-drv.c b/drivers/char/hw_random/n2-drv.c index 92dd4e925315..f8411515fe1c 100644 --- a/drivers/char/hw_random/n2-drv.c +++ b/drivers/char/hw_random/n2-drv.c @@ -435,7 +435,7 @@ static int n2rng_data_read(struct hwrng *rng, u32 *data) *data = np->test_data & 0xffffffff; len = 4; } else { - dev_err(&np->op->dev, "RNG error, restesting\n"); + dev_err(&np->op->dev, "RNG error, retesting\n"); np->flags &= ~N2RNG_FLAG_READY; if (!(np->flags & N2RNG_FLAG_SHUTDOWN)) schedule_delayed_work(&np->work, 0); diff --git a/drivers/char/hw_random/stm32-rng.c b/drivers/char/hw_random/stm32-rng.c index 0d2328da3b76..042860d97b15 100644 --- a/drivers/char/hw_random/stm32-rng.c +++ b/drivers/char/hw_random/stm32-rng.c @@ -187,8 +187,13 @@ static int stm32_rng_runtime_resume(struct device *dev) } #endif -static UNIVERSAL_DEV_PM_OPS(stm32_rng_pm_ops, stm32_rng_runtime_suspend, - stm32_rng_runtime_resume, NULL); +static const struct dev_pm_ops stm32_rng_pm_ops = { + SET_RUNTIME_PM_OPS(stm32_rng_runtime_suspend, + stm32_rng_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + static const struct of_device_id stm32_rng_match[] = { { diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c index 6e9df558325b..ffe9b0c6c647 100644 --- a/drivers/char/hw_random/via-rng.c +++ b/drivers/char/hw_random/via-rng.c @@ -135,7 +135,7 @@ static int via_rng_init(struct hwrng *rng) * is always enabled if CPUID rng_en is set. There is no * RNG configuration like it used to be the case in this * register */ - if ((c->x86 == 6) && (c->x86_model >= 0x0f)) { + if (((c->x86 == 6) && (c->x86_model >= 0x0f)) || (c->x86 > 6)){ if (!boot_cpu_has(X86_FEATURE_XSTORE_EN)) { pr_err(PFX "can't enable hardware RNG " "if XSTORE is not enabled\n"); diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 1bb9e7cc82e3..53cfe574d8d4 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -95,19 +95,6 @@ static const struct seq_operations misc_seq_ops = { .stop = misc_seq_stop, .show = misc_seq_show, }; - -static int misc_seq_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &misc_seq_ops); -} - -static const struct file_operations misc_proc_fops = { - .owner = THIS_MODULE, - .open = misc_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; #endif static int misc_open(struct inode *inode, struct file *file) @@ -282,7 +269,7 @@ static int __init misc_init(void) int err; struct proc_dir_entry *ret; - ret = proc_create("misc", 0, NULL, &misc_proc_fops); + ret = proc_create_seq("misc", 0, NULL, &misc_seq_ops); misc_class = class_create(THIS_MODULE, "misc"); err = PTR_ERR(misc_class); if (IS_ERR(misc_class)) diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c index 678fa97e41fb..25264d65e716 100644 --- a/drivers/char/nvram.c +++ b/drivers/char/nvram.c @@ -389,22 +389,9 @@ static int nvram_proc_read(struct seq_file *seq, void *offset) return 0; } -static int nvram_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, nvram_proc_read, NULL); -} - -static const struct file_operations nvram_proc_fops = { - .owner = THIS_MODULE, - .open = nvram_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static int nvram_add_proc_fs(void) { - if (!proc_create("driver/nvram", 0, NULL, &nvram_proc_fops)) + if (!proc_create_single("driver/nvram", 0, NULL, nvram_proc_read)) return -ENOMEM; return 0; } diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index aa502e9fb7fa..66b04194aa9f 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -2616,19 +2616,6 @@ static int mgslpc_proc_show(struct seq_file *m, void *v) return 0; } -static int mgslpc_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, mgslpc_proc_show, NULL); -} - -static const struct file_operations mgslpc_proc_fops = { - .owner = THIS_MODULE, - .open = mgslpc_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static int rx_alloc_buffers(MGSLPC_INFO *info) { /* each buffer has header and data */ @@ -2815,7 +2802,7 @@ static const struct tty_operations mgslpc_ops = { .tiocmget = tiocmget, .tiocmset = tiocmset, .get_icount = mgslpc_get_icount, - .proc_fops = &mgslpc_proc_fops, + .proc_show = mgslpc_proc_show, }; static int __init synclink_cs_init(void) diff --git a/drivers/char/random.c b/drivers/char/random.c index cd888d4ee605..a8fb0020ba5c 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -402,8 +402,7 @@ static struct poolinfo { /* * Static global variables */ -static DECLARE_WAIT_QUEUE_HEAD(random_read_wait); -static DECLARE_WAIT_QUEUE_HEAD(random_write_wait); +static DECLARE_WAIT_QUEUE_HEAD(random_wait); static struct fasync_struct *fasync; static DEFINE_SPINLOCK(random_ready_list_lock); @@ -722,8 +721,8 @@ retry: /* should we wake readers? */ if (entropy_bits >= random_read_wakeup_bits && - wq_has_sleeper(&random_read_wait)) { - wake_up_interruptible(&random_read_wait); + wq_has_sleeper(&random_wait)) { + wake_up_interruptible_poll(&random_wait, POLLIN); kill_fasync(&fasync, SIGIO, POLL_IN); } /* If the input pool is getting full, send some @@ -1397,7 +1396,7 @@ retry: trace_debit_entropy(r->name, 8 * ibytes); if (ibytes && (r->entropy_count >> ENTROPY_SHIFT) < random_write_wakeup_bits) { - wake_up_interruptible(&random_write_wait); + wake_up_interruptible_poll(&random_wait, POLLOUT); kill_fasync(&fasync, SIGIO, POLL_OUT); } @@ -1839,7 +1838,7 @@ _random_read(int nonblock, char __user *buf, size_t nbytes) if (nonblock) return -EAGAIN; - wait_event_interruptible(random_read_wait, + wait_event_interruptible(random_wait, ENTROPY_BITS(&input_pool) >= random_read_wakeup_bits); if (signal_pending(current)) @@ -1876,14 +1875,17 @@ urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) return ret; } +static struct wait_queue_head * +random_get_poll_head(struct file *file, __poll_t events) +{ + return &random_wait; +} + static __poll_t -random_poll(struct file *file, poll_table * wait) +random_poll_mask(struct file *file, __poll_t events) { - __poll_t mask; + __poll_t mask = 0; - poll_wait(file, &random_read_wait, wait); - poll_wait(file, &random_write_wait, wait); - mask = 0; if (ENTROPY_BITS(&input_pool) >= random_read_wakeup_bits) mask |= EPOLLIN | EPOLLRDNORM; if (ENTROPY_BITS(&input_pool) < random_write_wakeup_bits) @@ -1990,7 +1992,8 @@ static int random_fasync(int fd, struct file *filp, int on) const struct file_operations random_fops = { .read = random_read, .write = random_write, - .poll = random_poll, + .get_poll_head = random_get_poll_head, + .poll_mask = random_poll_mask, .unlocked_ioctl = random_ioctl, .fasync = random_fasync, .llseek = noop_llseek, @@ -2323,7 +2326,7 @@ void add_hwgenerator_randomness(const char *buffer, size_t count, * We'll be woken up again once below random_write_wakeup_thresh, * or when the calling thread is about to terminate. */ - wait_event_interruptible(random_write_wait, kthread_should_stop() || + wait_event_interruptible(random_wait, kthread_should_stop() || ENTROPY_BITS(&input_pool) <= random_write_wakeup_bits); mix_pool_bytes(poolp, buffer, count); credit_entropy_bits(poolp, entropy); diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index 57dc546628b5..94fedeeec035 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -171,7 +171,7 @@ static void mask_rtc_irq_bit(unsigned char bit) #endif #ifdef CONFIG_PROC_FS -static int rtc_proc_open(struct inode *inode, struct file *file); +static int rtc_proc_show(struct seq_file *seq, void *v); #endif /* @@ -832,16 +832,6 @@ static struct miscdevice rtc_dev = { .fops = &rtc_fops, }; -#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, -}; -#endif - static resource_size_t rtc_size; static struct resource * __init rtc_request_region(resource_size_t size) @@ -982,7 +972,7 @@ no_irq: } #ifdef CONFIG_PROC_FS - ent = proc_create("driver/rtc", 0, NULL, &rtc_proc_fops); + ent = proc_create_single("driver/rtc", 0, NULL, rtc_proc_show); if (!ent) printk(KERN_WARNING "rtc: Failed to register with procfs.\n"); #endif @@ -1201,11 +1191,6 @@ static int rtc_proc_show(struct seq_file *seq, void *v) #undef YN #undef NY } - -static int rtc_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, rtc_proc_show, NULL); -} #endif static void rtc_get_rtc_time(struct rtc_time *rtc_tm) diff --git a/drivers/char/toshiba.c b/drivers/char/toshiba.c index 5488516da8ea..802376fe851a 100644 --- a/drivers/char/toshiba.c +++ b/drivers/char/toshiba.c @@ -326,19 +326,6 @@ static int proc_toshiba_show(struct seq_file *m, void *v) key); return 0; } - -static int proc_toshiba_open(struct inode *inode, struct file *file) -{ - return single_open(file, proc_toshiba_show, NULL); -} - -static const struct file_operations proc_toshiba_fops = { - .owner = THIS_MODULE, - .open = proc_toshiba_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; #endif @@ -524,7 +511,7 @@ static int __init toshiba_init(void) { struct proc_dir_entry *pde; - pde = proc_create("toshiba", 0, NULL, &proc_toshiba_fops); + pde = proc_create_single("toshiba", 0, NULL, proc_toshiba_show); if (!pde) { misc_deregister(&tosh_device); return -ENOMEM; diff --git a/drivers/clk/x86/Makefile b/drivers/clk/x86/Makefile index 1367afb03858..00303bc05415 100644 --- a/drivers/clk/x86/Makefile +++ b/drivers/clk/x86/Makefile @@ -1,3 +1,4 @@ +obj-$(CONFIG_PMC_ATOM) += clk-pmc-atom.o +obj-$(CONFIG_X86_AMD_PLATFORM_DEVICE) += clk-st.o clk-x86-lpss-objs := clk-lpt.o obj-$(CONFIG_X86_INTEL_LPSS) += clk-x86-lpss.o -obj-$(CONFIG_PMC_ATOM) += clk-pmc-atom.o diff --git a/drivers/clk/x86/clk-st.c b/drivers/clk/x86/clk-st.c new file mode 100644 index 000000000000..fb62f3938008 --- /dev/null +++ b/drivers/clk/x86/clk-st.c @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: MIT +/* + * clock framework for AMD Stoney based clocks + * + * Copyright 2018 Advanced Micro Devices, Inc. + */ + +#include <linux/clk.h> +#include <linux/clkdev.h> +#include <linux/clk-provider.h> +#include <linux/platform_data/clk-st.h> +#include <linux/platform_device.h> + +/* Clock Driving Strength 2 register */ +#define CLKDRVSTR2 0x28 +/* Clock Control 1 register */ +#define MISCCLKCNTL1 0x40 +/* Auxiliary clock1 enable bit */ +#define OSCCLKENB 2 +/* 25Mhz auxiliary output clock freq bit */ +#define OSCOUT1CLK25MHZ 16 + +#define ST_CLK_48M 0 +#define ST_CLK_25M 1 +#define ST_CLK_MUX 2 +#define ST_CLK_GATE 3 +#define ST_MAX_CLKS 4 + +static const char * const clk_oscout1_parents[] = { "clk48MHz", "clk25MHz" }; +static struct clk_hw *hws[ST_MAX_CLKS]; + +static int st_clk_probe(struct platform_device *pdev) +{ + struct st_clk_data *st_data; + + st_data = dev_get_platdata(&pdev->dev); + if (!st_data || !st_data->base) + return -EINVAL; + + hws[ST_CLK_48M] = clk_hw_register_fixed_rate(NULL, "clk48MHz", NULL, 0, + 48000000); + hws[ST_CLK_25M] = clk_hw_register_fixed_rate(NULL, "clk25MHz", NULL, 0, + 25000000); + + hws[ST_CLK_MUX] = clk_hw_register_mux(NULL, "oscout1_mux", + clk_oscout1_parents, ARRAY_SIZE(clk_oscout1_parents), + 0, st_data->base + CLKDRVSTR2, OSCOUT1CLK25MHZ, 3, 0, NULL); + + clk_set_parent(hws[ST_CLK_MUX]->clk, hws[ST_CLK_25M]->clk); + + hws[ST_CLK_GATE] = clk_hw_register_gate(NULL, "oscout1", "oscout1_mux", + 0, st_data->base + MISCCLKCNTL1, OSCCLKENB, + CLK_GATE_SET_TO_DISABLE, NULL); + + clk_hw_register_clkdev(hws[ST_CLK_GATE], "oscout1", NULL); + + return 0; +} + +static int st_clk_remove(struct platform_device *pdev) +{ + int i; + + for (i = 0; i < ST_MAX_CLKS; i++) + clk_hw_unregister(hws[i]); + return 0; +} + +static struct platform_driver st_clk_driver = { + .driver = { + .name = "clk-st", + .suppress_bind_attrs = true, + }, + .probe = st_clk_probe, + .remove = st_clk_remove, +}; +builtin_platform_driver(st_clk_driver); diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 8e8a09755d10..dec0dd88ec15 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -450,8 +450,10 @@ config MTK_TIMER Support for Mediatek timer driver. config SPRD_TIMER - bool "Spreadtrum timer driver" if COMPILE_TEST + bool "Spreadtrum timer driver" if EXPERT depends on HAS_IOMEM + depends on (ARCH_SPRD || COMPILE_TEST) + default ARCH_SPRD select TIMER_OF help Enables support for the Spreadtrum timer driver. diff --git a/drivers/clocksource/arc_timer.c b/drivers/clocksource/arc_timer.c index 471b428d8034..20da9b1d7f7d 100644 --- a/drivers/clocksource/arc_timer.c +++ b/drivers/clocksource/arc_timer.c @@ -61,6 +61,20 @@ static u64 arc_read_gfrc(struct clocksource *cs) unsigned long flags; u32 l, h; + /* + * From a programming model pov, there seems to be just one instance of + * MCIP_CMD/MCIP_READBACK however micro-architecturally there's + * an instance PER ARC CORE (not per cluster), and there are dedicated + * hardware decode logic (per core) inside ARConnect to handle + * simultaneous read/write accesses from cores via those two registers. + * So several concurrent commands to ARConnect are OK if they are + * trying to access two different sub-components (like GFRC, + * inter-core interrupt, etc...). HW also supports simultaneously + * accessing GFRC by multiple cores. + * That's why it is safe to disable hard interrupts on the local CPU + * before access to GFRC instead of taking global MCIP spinlock + * defined in arch/arc/kernel/mcip.c + */ local_irq_save(flags); __mcip_cmd(CMD_GFRC_READ_LO, 0); diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c index 986b6796b631..54f8a331b53a 100644 --- a/drivers/clocksource/mips-gic-timer.c +++ b/drivers/clocksource/mips-gic-timer.c @@ -5,6 +5,9 @@ * * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. */ + +#define pr_fmt(fmt) "mips-gic-timer: " fmt + #include <linux/clk.h> #include <linux/clockchips.h> #include <linux/cpu.h> @@ -136,8 +139,7 @@ static int gic_clockevent_init(void) ret = setup_percpu_irq(gic_timer_irq, &gic_compare_irqaction); if (ret < 0) { - pr_err("GIC timer IRQ %d setup failed: %d\n", - gic_timer_irq, ret); + pr_err("IRQ %d setup failed (%d)\n", gic_timer_irq, ret); return ret; } @@ -176,7 +178,7 @@ static int __init __gic_clocksource_init(void) ret = clocksource_register_hz(&gic_clocksource, gic_frequency); if (ret < 0) - pr_warn("GIC: Unable to register clocksource\n"); + pr_warn("Unable to register clocksource\n"); return ret; } @@ -188,7 +190,7 @@ static int __init gic_clocksource_of_init(struct device_node *node) if (!mips_gic_present() || !node->parent || !of_device_is_compatible(node->parent, "mti,gic")) { - pr_warn("No DT definition for the mips gic driver\n"); + pr_warn("No DT definition\n"); return -ENXIO; } @@ -196,7 +198,7 @@ static int __init gic_clocksource_of_init(struct device_node *node) if (!IS_ERR(clk)) { ret = clk_prepare_enable(clk); if (ret < 0) { - pr_err("GIC failed to enable clock\n"); + pr_err("Failed to enable clock\n"); clk_put(clk); return ret; } @@ -204,12 +206,12 @@ static int __init gic_clocksource_of_init(struct device_node *node) gic_frequency = clk_get_rate(clk); } else if (of_property_read_u32(node, "clock-frequency", &gic_frequency)) { - pr_err("GIC frequency not specified.\n"); + pr_err("Frequency not specified\n"); return -EINVAL; } gic_timer_irq = irq_of_parse_and_map(node, 0); if (!gic_timer_irq) { - pr_err("GIC timer IRQ not specified.\n"); + pr_err("IRQ not specified\n"); return -EINVAL; } @@ -220,7 +222,7 @@ static int __init gic_clocksource_of_init(struct device_node *node) ret = gic_clockevent_init(); if (!ret && !IS_ERR(clk)) { if (clk_notifier_register(clk, &gic_clk_nb) < 0) - pr_warn("GIC: Unable to register clock notifier\n"); + pr_warn("Unable to register clock notifier\n"); } /* And finally start the counter */ diff --git a/drivers/clocksource/mxs_timer.c b/drivers/clocksource/mxs_timer.c index a03434e9fe8f..f6ddae30933f 100644 --- a/drivers/clocksource/mxs_timer.c +++ b/drivers/clocksource/mxs_timer.c @@ -1,24 +1,10 @@ -/* - * Copyright (C) 2000-2001 Deep Blue Solutions - * Copyright (C) 2002 Shane Nay (shane@minirl.com) - * Copyright (C) 2006-2007 Pavel Pisa (ppisa@pikron.com) - * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de) - * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (C) 2000-2001 Deep Blue Solutions +// Copyright (C) 2002 Shane Nay (shane@minirl.com) +// Copyright (C) 2006-2007 Pavel Pisa (ppisa@pikron.com) +// Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de) +// Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved. #include <linux/err.h> #include <linux/interrupt.h> diff --git a/drivers/clocksource/timer-imx-gpt.c b/drivers/clocksource/timer-imx-gpt.c index 6ec6d79b237c..165fbbb1c9a0 100644 --- a/drivers/clocksource/timer-imx-gpt.c +++ b/drivers/clocksource/timer-imx-gpt.c @@ -1,25 +1,9 @@ -/* - * linux/arch/arm/plat-mxc/time.c - * - * Copyright (C) 2000-2001 Deep Blue Solutions - * Copyright (C) 2002 Shane Nay (shane@minirl.com) - * Copyright (C) 2006-2007 Pavel Pisa (ppisa@pikron.com) - * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.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., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (C) 2000-2001 Deep Blue Solutions +// Copyright (C) 2002 Shane Nay (shane@minirl.com) +// Copyright (C) 2006-2007 Pavel Pisa (ppisa@pikron.com) +// Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de) #include <linux/interrupt.h> #include <linux/irq.h> diff --git a/drivers/clocksource/timer-imx-tpm.c b/drivers/clocksource/timer-imx-tpm.c index 6c8318470b48..b7aa2b817078 100644 --- a/drivers/clocksource/timer-imx-tpm.c +++ b/drivers/clocksource/timer-imx-tpm.c @@ -1,12 +1,7 @@ -/* - * Copyright 2016 Freescale Semiconductor, Inc. - * Copyright 2017 NXP - * - * 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. - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright 2016 Freescale Semiconductor, Inc. +// Copyright 2017 NXP #include <linux/clk.h> #include <linux/clockchips.h> diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c index 8615594bd065..e718b8c69a56 100644 --- a/drivers/connector/connector.c +++ b/drivers/connector/connector.c @@ -260,19 +260,6 @@ static int cn_proc_show(struct seq_file *m, void *v) return 0; } -static int cn_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, cn_proc_show, NULL); -} - -static const struct file_operations cn_file_ops = { - .owner = THIS_MODULE, - .open = cn_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release -}; - static struct cn_dev cdev = { .input = cn_rx_skb, }; @@ -297,7 +284,7 @@ static int cn_init(void) cn_already_initialized = 1; - proc_create("connector", S_IRUGO, init_net.proc_net, &cn_file_ops); + proc_create_single("connector", S_IRUGO, init_net.proc_net, cn_proc_show); return 0; } diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 96b35b8b3606..c7ce928fbf1f 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -124,6 +124,17 @@ config ARM_OMAP2PLUS_CPUFREQ depends on ARCH_OMAP2PLUS default ARCH_OMAP2PLUS +config ARM_QCOM_CPUFREQ_KRYO + bool "Qualcomm Kryo based CPUFreq" + depends on ARM64 + depends on QCOM_QFPROM + depends on QCOM_SMEM + select PM_OPP + help + This adds the CPUFreq driver for Qualcomm Kryo SoC based boards. + + If in doubt, say N. + config ARM_S3C_CPUFREQ bool help @@ -264,7 +275,7 @@ config ARM_TANGO_CPUFREQ default y config ARM_TEGRA20_CPUFREQ - bool "Tegra20 CPUFreq support" + tristate "Tegra20 CPUFreq support" depends on ARCH_TEGRA default y help diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 8d24ade3bd02..fb4a2ecac43b 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -65,6 +65,7 @@ obj-$(CONFIG_MACH_MVEBU_V7) += mvebu-cpufreq.o obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ) += omap-cpufreq.o obj-$(CONFIG_ARM_PXA2xx_CPUFREQ) += pxa2xx-cpufreq.o obj-$(CONFIG_PXA3xx) += pxa3xx-cpufreq.o +obj-$(CONFIG_ARM_QCOM_CPUFREQ_KRYO) += qcom-cpufreq-kryo.o obj-$(CONFIG_ARM_S3C2410_CPUFREQ) += s3c2410-cpufreq.o obj-$(CONFIG_ARM_S3C2412_CPUFREQ) += s3c2412-cpufreq.o obj-$(CONFIG_ARM_S3C2416_CPUFREQ) += s3c2416-cpufreq.o diff --git a/drivers/cpufreq/armada-37xx-cpufreq.c b/drivers/cpufreq/armada-37xx-cpufreq.c index 72a2975499db..739da90ff3f6 100644 --- a/drivers/cpufreq/armada-37xx-cpufreq.c +++ b/drivers/cpufreq/armada-37xx-cpufreq.c @@ -23,6 +23,8 @@ #include <linux/regmap.h> #include <linux/slab.h> +#include "cpufreq-dt.h" + /* Power management in North Bridge register set */ #define ARMADA_37XX_NB_L0L1 0x18 #define ARMADA_37XX_NB_L2L3 0x1C @@ -56,6 +58,16 @@ */ #define LOAD_LEVEL_NR 4 +struct armada37xx_cpufreq_state { + struct regmap *regmap; + u32 nb_l0l1; + u32 nb_l2l3; + u32 nb_dyn_mod; + u32 nb_cpu_load; +}; + +static struct armada37xx_cpufreq_state *armada37xx_cpufreq_state; + struct armada_37xx_dvfs { u32 cpu_freq_max; u8 divider[LOAD_LEVEL_NR]; @@ -136,7 +148,7 @@ static void __init armada37xx_cpufreq_dvfs_setup(struct regmap *base, clk_set_parent(clk, parent); } -static void __init armada37xx_cpufreq_disable_dvfs(struct regmap *base) +static void armada37xx_cpufreq_disable_dvfs(struct regmap *base) { unsigned int reg = ARMADA_37XX_NB_DYN_MOD, mask = ARMADA_37XX_NB_DFS_EN; @@ -162,10 +174,47 @@ static void __init armada37xx_cpufreq_enable_dvfs(struct regmap *base) regmap_update_bits(base, reg, mask, mask); } +static int armada37xx_cpufreq_suspend(struct cpufreq_policy *policy) +{ + struct armada37xx_cpufreq_state *state = armada37xx_cpufreq_state; + + regmap_read(state->regmap, ARMADA_37XX_NB_L0L1, &state->nb_l0l1); + regmap_read(state->regmap, ARMADA_37XX_NB_L2L3, &state->nb_l2l3); + regmap_read(state->regmap, ARMADA_37XX_NB_CPU_LOAD, + &state->nb_cpu_load); + regmap_read(state->regmap, ARMADA_37XX_NB_DYN_MOD, &state->nb_dyn_mod); + + return 0; +} + +static int armada37xx_cpufreq_resume(struct cpufreq_policy *policy) +{ + struct armada37xx_cpufreq_state *state = armada37xx_cpufreq_state; + + /* Ensure DVFS is disabled otherwise the following registers are RO */ + armada37xx_cpufreq_disable_dvfs(state->regmap); + + regmap_write(state->regmap, ARMADA_37XX_NB_L0L1, state->nb_l0l1); + regmap_write(state->regmap, ARMADA_37XX_NB_L2L3, state->nb_l2l3); + regmap_write(state->regmap, ARMADA_37XX_NB_CPU_LOAD, + state->nb_cpu_load); + + /* + * NB_DYN_MOD register is the one that actually enable back DVFS if it + * was enabled before the suspend operation. This must be done last + * otherwise other registers are not writable. + */ + regmap_write(state->regmap, ARMADA_37XX_NB_DYN_MOD, state->nb_dyn_mod); + + return 0; +} + static int __init armada37xx_cpufreq_driver_init(void) { + struct cpufreq_dt_platform_data pdata; struct armada_37xx_dvfs *dvfs; struct platform_device *pdev; + unsigned long freq; unsigned int cur_frequency; struct regmap *nb_pm_base; struct device *cpu_dev; @@ -207,33 +256,58 @@ static int __init armada37xx_cpufreq_driver_init(void) } dvfs = armada_37xx_cpu_freq_info_get(cur_frequency); - if (!dvfs) + if (!dvfs) { + clk_put(clk); return -EINVAL; + } + + armada37xx_cpufreq_state = kmalloc(sizeof(*armada37xx_cpufreq_state), + GFP_KERNEL); + if (!armada37xx_cpufreq_state) { + clk_put(clk); + return -ENOMEM; + } + + armada37xx_cpufreq_state->regmap = nb_pm_base; armada37xx_cpufreq_dvfs_setup(nb_pm_base, clk, dvfs->divider); clk_put(clk); for (load_lvl = ARMADA_37XX_DVFS_LOAD_0; load_lvl < LOAD_LEVEL_NR; load_lvl++) { - unsigned long freq = cur_frequency / dvfs->divider[load_lvl]; + freq = cur_frequency / dvfs->divider[load_lvl]; ret = dev_pm_opp_add(cpu_dev, freq, 0); - if (ret) { - /* clean-up the already added opp before leaving */ - while (load_lvl-- > ARMADA_37XX_DVFS_LOAD_0) { - freq = cur_frequency / dvfs->divider[load_lvl]; - dev_pm_opp_remove(cpu_dev, freq); - } - return ret; - } + if (ret) + goto remove_opp; } /* Now that everything is setup, enable the DVFS at hardware level */ armada37xx_cpufreq_enable_dvfs(nb_pm_base); - pdev = platform_device_register_simple("cpufreq-dt", -1, NULL, 0); + pdata.suspend = armada37xx_cpufreq_suspend; + pdata.resume = armada37xx_cpufreq_resume; + + pdev = platform_device_register_data(NULL, "cpufreq-dt", -1, &pdata, + sizeof(pdata)); + ret = PTR_ERR_OR_ZERO(pdev); + if (ret) + goto disable_dvfs; + + return 0; + +disable_dvfs: + armada37xx_cpufreq_disable_dvfs(nb_pm_base); +remove_opp: + /* clean-up the already added opp before leaving */ + while (load_lvl-- > ARMADA_37XX_DVFS_LOAD_0) { + freq = cur_frequency / dvfs->divider[load_lvl]; + dev_pm_opp_remove(cpu_dev, freq); + } + + kfree(armada37xx_cpufreq_state); - return PTR_ERR_OR_ZERO(pdev); + return ret; } /* late_initcall, to guarantee the driver is loaded after A37xx clock driver */ late_initcall(armada37xx_cpufreq_driver_init); diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c index b15115a48775..3464580ac3ca 100644 --- a/drivers/cpufreq/cppc_cpufreq.c +++ b/drivers/cpufreq/cppc_cpufreq.c @@ -42,9 +42,6 @@ */ static struct cppc_cpudata **all_cpu_data; -/* Capture the max KHz from DMI */ -static u64 cppc_dmi_max_khz; - /* Callback function used to retrieve the max frequency from DMI */ static void cppc_find_dmi_mhz(const struct dmi_header *dm, void *private) { @@ -75,6 +72,64 @@ static u64 cppc_get_dmi_max_khz(void) return (1000 * mhz); } +/* + * If CPPC lowest_freq and nominal_freq registers are exposed then we can + * use them to convert perf to freq and vice versa + * + * If the perf/freq point lies between Nominal and Lowest, we can treat + * (Low perf, Low freq) and (Nom Perf, Nom freq) as 2D co-ordinates of a line + * and extrapolate the rest + * For perf/freq > Nominal, we use the ratio perf:freq at Nominal for conversion + */ +static unsigned int cppc_cpufreq_perf_to_khz(struct cppc_cpudata *cpu, + unsigned int perf) +{ + static u64 max_khz; + struct cppc_perf_caps *caps = &cpu->perf_caps; + u64 mul, div; + + if (caps->lowest_freq && caps->nominal_freq) { + if (perf >= caps->nominal_perf) { + mul = caps->nominal_freq; + div = caps->nominal_perf; + } else { + mul = caps->nominal_freq - caps->lowest_freq; + div = caps->nominal_perf - caps->lowest_perf; + } + } else { + if (!max_khz) + max_khz = cppc_get_dmi_max_khz(); + mul = max_khz; + div = cpu->perf_caps.highest_perf; + } + return (u64)perf * mul / div; +} + +static unsigned int cppc_cpufreq_khz_to_perf(struct cppc_cpudata *cpu, + unsigned int freq) +{ + static u64 max_khz; + struct cppc_perf_caps *caps = &cpu->perf_caps; + u64 mul, div; + + if (caps->lowest_freq && caps->nominal_freq) { + if (freq >= caps->nominal_freq) { + mul = caps->nominal_perf; + div = caps->nominal_freq; + } else { + mul = caps->lowest_perf; + div = caps->lowest_freq; + } + } else { + if (!max_khz) + max_khz = cppc_get_dmi_max_khz(); + mul = cpu->perf_caps.highest_perf; + div = max_khz; + } + + return (u64)freq * mul / div; +} + static int cppc_cpufreq_set_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation) @@ -86,7 +141,7 @@ static int cppc_cpufreq_set_target(struct cpufreq_policy *policy, cpu = all_cpu_data[policy->cpu]; - desired_perf = (u64)target_freq * cpu->perf_caps.highest_perf / cppc_dmi_max_khz; + desired_perf = cppc_cpufreq_khz_to_perf(cpu, target_freq); /* Return if it is exactly the same perf */ if (desired_perf == cpu->perf_ctrls.desired_perf) return ret; @@ -186,24 +241,24 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy) return ret; } - cppc_dmi_max_khz = cppc_get_dmi_max_khz(); + /* Convert the lowest and nominal freq from MHz to KHz */ + cpu->perf_caps.lowest_freq *= 1000; + cpu->perf_caps.nominal_freq *= 1000; /* * Set min to lowest nonlinear perf to avoid any efficiency penalty (see * Section 8.4.7.1.1.5 of ACPI 6.1 spec) */ - policy->min = cpu->perf_caps.lowest_nonlinear_perf * cppc_dmi_max_khz / - cpu->perf_caps.highest_perf; - policy->max = cppc_dmi_max_khz; + policy->min = cppc_cpufreq_perf_to_khz(cpu, cpu->perf_caps.lowest_nonlinear_perf); + policy->max = cppc_cpufreq_perf_to_khz(cpu, cpu->perf_caps.highest_perf); /* * Set cpuinfo.min_freq to Lowest to make the full range of performance * available if userspace wants to use any perf between lowest & lowest * nonlinear perf */ - policy->cpuinfo.min_freq = cpu->perf_caps.lowest_perf * cppc_dmi_max_khz / - cpu->perf_caps.highest_perf; - policy->cpuinfo.max_freq = cppc_dmi_max_khz; + policy->cpuinfo.min_freq = cppc_cpufreq_perf_to_khz(cpu, cpu->perf_caps.lowest_perf); + policy->cpuinfo.max_freq = cppc_cpufreq_perf_to_khz(cpu, cpu->perf_caps.highest_perf); policy->transition_delay_us = cppc_cpufreq_get_transition_delay_us(cpu_num); policy->shared_type = cpu->shared_type; @@ -229,7 +284,8 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy) cpu->cur_policy = policy; /* Set policy->cur to max now. The governors will adjust later. */ - policy->cur = cppc_dmi_max_khz; + policy->cur = cppc_cpufreq_perf_to_khz(cpu, + cpu->perf_caps.highest_perf); cpu->perf_ctrls.desired_perf = cpu->perf_caps.highest_perf; ret = cppc_set_perf(cpu_num, &cpu->perf_ctrls); diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c index 3b585e4bfac5..fe14c57de6ca 100644 --- a/drivers/cpufreq/cpufreq-dt-platdev.c +++ b/drivers/cpufreq/cpufreq-dt-platdev.c @@ -66,8 +66,6 @@ static const struct of_device_id whitelist[] __initconst = { { .compatible = "renesas,r8a7792", }, { .compatible = "renesas,r8a7793", }, { .compatible = "renesas,r8a7794", }, - { .compatible = "renesas,r8a7795", }, - { .compatible = "renesas,r8a7796", }, { .compatible = "renesas,sh73a0", }, { .compatible = "rockchip,rk2928", }, @@ -118,6 +116,9 @@ static const struct of_device_id blacklist[] __initconst = { { .compatible = "nvidia,tegra124", }, + { .compatible = "qcom,apq8096", }, + { .compatible = "qcom,msm8996", }, + { .compatible = "st,stih407", }, { .compatible = "st,stih410", }, diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c index 190ea0dccb79..0a9ebf00be46 100644 --- a/drivers/cpufreq/cpufreq-dt.c +++ b/drivers/cpufreq/cpufreq-dt.c @@ -346,8 +346,14 @@ static int dt_cpufreq_probe(struct platform_device *pdev) if (ret) return ret; - if (data && data->have_governor_per_policy) - dt_cpufreq_driver.flags |= CPUFREQ_HAVE_GOVERNOR_PER_POLICY; + if (data) { + if (data->have_governor_per_policy) + dt_cpufreq_driver.flags |= CPUFREQ_HAVE_GOVERNOR_PER_POLICY; + + dt_cpufreq_driver.resume = data->resume; + if (data->suspend) + dt_cpufreq_driver.suspend = data->suspend; + } ret = cpufreq_register_driver(&dt_cpufreq_driver); if (ret) diff --git a/drivers/cpufreq/cpufreq-dt.h b/drivers/cpufreq/cpufreq-dt.h index 54d774e46c43..d5aeea13433e 100644 --- a/drivers/cpufreq/cpufreq-dt.h +++ b/drivers/cpufreq/cpufreq-dt.h @@ -12,8 +12,13 @@ #include <linux/types.h> +struct cpufreq_policy; + struct cpufreq_dt_platform_data { bool have_governor_per_policy; + + int (*suspend)(struct cpufreq_policy *policy); + int (*resume)(struct cpufreq_policy *policy); }; #endif /* __CPUFREQ_DT_H__ */ diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 075d18f6ba7a..b0dfd3222013 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -89,16 +89,7 @@ static void cpufreq_governor_limits(struct cpufreq_policy *policy); * The mutex locks both lists. */ static BLOCKING_NOTIFIER_HEAD(cpufreq_policy_notifier_list); -static struct srcu_notifier_head cpufreq_transition_notifier_list; - -static bool init_cpufreq_transition_notifier_list_called; -static int __init init_cpufreq_transition_notifier_list(void) -{ - srcu_init_notifier_head(&cpufreq_transition_notifier_list); - init_cpufreq_transition_notifier_list_called = true; - return 0; -} -pure_initcall(init_cpufreq_transition_notifier_list); +SRCU_NOTIFIER_HEAD_STATIC(cpufreq_transition_notifier_list); static int off __read_mostly; static int cpufreq_disabled(void) @@ -300,8 +291,19 @@ static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) #endif } -static void __cpufreq_notify_transition(struct cpufreq_policy *policy, - struct cpufreq_freqs *freqs, unsigned int state) +/** + * cpufreq_notify_transition - Notify frequency transition and adjust_jiffies. + * @policy: cpufreq policy to enable fast frequency switching for. + * @freqs: contain details of the frequency update. + * @state: set to CPUFREQ_PRECHANGE or CPUFREQ_POSTCHANGE. + * + * This function calls the transition notifiers and the "adjust_jiffies" + * function. It is called twice on all CPU frequency changes that have + * external effects. + */ +static void cpufreq_notify_transition(struct cpufreq_policy *policy, + struct cpufreq_freqs *freqs, + unsigned int state) { BUG_ON(irqs_disabled()); @@ -313,54 +315,44 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy, state, freqs->new); switch (state) { - case CPUFREQ_PRECHANGE: - /* detect if the driver reported a value as "old frequency" + /* + * Detect if the driver reported a value as "old frequency" * which is not equal to what the cpufreq core thinks is * "old frequency". */ if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) { - if ((policy) && (policy->cpu == freqs->cpu) && - (policy->cur) && (policy->cur != freqs->old)) { + if (policy->cur && (policy->cur != freqs->old)) { pr_debug("Warning: CPU frequency is %u, cpufreq assumed %u kHz\n", freqs->old, policy->cur); freqs->old = policy->cur; } } - srcu_notifier_call_chain(&cpufreq_transition_notifier_list, - CPUFREQ_PRECHANGE, freqs); + + for_each_cpu(freqs->cpu, policy->cpus) { + srcu_notifier_call_chain(&cpufreq_transition_notifier_list, + CPUFREQ_PRECHANGE, freqs); + } + adjust_jiffies(CPUFREQ_PRECHANGE, freqs); break; case CPUFREQ_POSTCHANGE: adjust_jiffies(CPUFREQ_POSTCHANGE, freqs); - pr_debug("FREQ: %lu - CPU: %lu\n", - (unsigned long)freqs->new, (unsigned long)freqs->cpu); - trace_cpu_frequency(freqs->new, freqs->cpu); + pr_debug("FREQ: %u - CPUs: %*pbl\n", freqs->new, + cpumask_pr_args(policy->cpus)); + + for_each_cpu(freqs->cpu, policy->cpus) { + trace_cpu_frequency(freqs->new, freqs->cpu); + srcu_notifier_call_chain(&cpufreq_transition_notifier_list, + CPUFREQ_POSTCHANGE, freqs); + } + cpufreq_stats_record_transition(policy, freqs->new); - srcu_notifier_call_chain(&cpufreq_transition_notifier_list, - CPUFREQ_POSTCHANGE, freqs); - if (likely(policy) && likely(policy->cpu == freqs->cpu)) - policy->cur = freqs->new; - break; + policy->cur = freqs->new; } } -/** - * cpufreq_notify_transition - call notifier chain and adjust_jiffies - * on frequency transition. - * - * This function calls the transition notifiers and the "adjust_jiffies" - * function. It is called twice on all CPU frequency changes that have - * external effects. - */ -static void cpufreq_notify_transition(struct cpufreq_policy *policy, - struct cpufreq_freqs *freqs, unsigned int state) -{ - for_each_cpu(freqs->cpu, policy->cpus) - __cpufreq_notify_transition(policy, freqs, state); -} - /* Do post notifications when there are chances that transition has failed */ static void cpufreq_notify_post_transition(struct cpufreq_policy *policy, struct cpufreq_freqs *freqs, int transition_failed) @@ -696,6 +688,8 @@ static ssize_t store_##file_name \ struct cpufreq_policy new_policy; \ \ memcpy(&new_policy, policy, sizeof(*policy)); \ + new_policy.min = policy->user_policy.min; \ + new_policy.max = policy->user_policy.max; \ \ ret = sscanf(buf, "%u", &new_policy.object); \ if (ret != 1) \ @@ -1764,8 +1758,6 @@ int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list) if (cpufreq_disabled()) return -EINVAL; - WARN_ON(!init_cpufreq_transition_notifier_list_called); - switch (list) { case CPUFREQ_TRANSITION_NOTIFIER: mutex_lock(&cpufreq_fast_switch_lock); diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index ca38229b045a..871bf9cf55cf 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -278,7 +278,7 @@ static void dbs_update_util_handler(struct update_util_data *data, u64 time, struct policy_dbs_info *policy_dbs = cdbs->policy_dbs; u64 delta_ns, lst; - if (!cpufreq_can_do_remote_dvfs(policy_dbs->policy)) + if (!cpufreq_this_cpu_can_update(policy_dbs->policy)) return; /* diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 17e566afbb41..08960a55eb27 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -1939,13 +1939,51 @@ static int intel_cpufreq_verify_policy(struct cpufreq_policy *policy) return 0; } +/* Use of trace in passive mode: + * + * In passive mode the trace core_busy field (also known as the + * performance field, and lablelled as such on the graphs; also known as + * core_avg_perf) is not needed and so is re-assigned to indicate if the + * driver call was via the normal or fast switch path. Various graphs + * output from the intel_pstate_tracer.py utility that include core_busy + * (or performance or core_avg_perf) have a fixed y-axis from 0 to 100%, + * so we use 10 to indicate the the normal path through the driver, and + * 90 to indicate the fast switch path through the driver. + * The scaled_busy field is not used, and is set to 0. + */ + +#define INTEL_PSTATE_TRACE_TARGET 10 +#define INTEL_PSTATE_TRACE_FAST_SWITCH 90 + +static void intel_cpufreq_trace(struct cpudata *cpu, unsigned int trace_type, int old_pstate) +{ + struct sample *sample; + + if (!trace_pstate_sample_enabled()) + return; + + if (!intel_pstate_sample(cpu, ktime_get())) + return; + + sample = &cpu->sample; + trace_pstate_sample(trace_type, + 0, + old_pstate, + cpu->pstate.current_pstate, + sample->mperf, + sample->aperf, + sample->tsc, + get_avg_frequency(cpu), + fp_toint(cpu->iowait_boost * 100)); +} + static int intel_cpufreq_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation) { struct cpudata *cpu = all_cpu_data[policy->cpu]; struct cpufreq_freqs freqs; - int target_pstate; + int target_pstate, old_pstate; update_turbo_state(); @@ -1965,12 +2003,14 @@ static int intel_cpufreq_target(struct cpufreq_policy *policy, break; } target_pstate = intel_pstate_prepare_request(cpu, target_pstate); + old_pstate = cpu->pstate.current_pstate; if (target_pstate != cpu->pstate.current_pstate) { cpu->pstate.current_pstate = target_pstate; wrmsrl_on_cpu(policy->cpu, MSR_IA32_PERF_CTL, pstate_funcs.get_val(cpu, target_pstate)); } freqs.new = target_pstate * cpu->pstate.scaling; + intel_cpufreq_trace(cpu, INTEL_PSTATE_TRACE_TARGET, old_pstate); cpufreq_freq_transition_end(policy, &freqs, false); return 0; @@ -1980,13 +2020,15 @@ static unsigned int intel_cpufreq_fast_switch(struct cpufreq_policy *policy, unsigned int target_freq) { struct cpudata *cpu = all_cpu_data[policy->cpu]; - int target_pstate; + int target_pstate, old_pstate; update_turbo_state(); target_pstate = DIV_ROUND_UP(target_freq, cpu->pstate.scaling); target_pstate = intel_pstate_prepare_request(cpu, target_pstate); + old_pstate = cpu->pstate.current_pstate; intel_pstate_update_pstate(cpu, target_pstate); + intel_cpufreq_trace(cpu, INTEL_PSTATE_TRACE_FAST_SWITCH, old_pstate); return target_pstate * cpu->pstate.scaling; } diff --git a/drivers/cpufreq/qcom-cpufreq-kryo.c b/drivers/cpufreq/qcom-cpufreq-kryo.c new file mode 100644 index 000000000000..d049fe4b80c4 --- /dev/null +++ b/drivers/cpufreq/qcom-cpufreq-kryo.c @@ -0,0 +1,212 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +/* + * In Certain QCOM SoCs like apq8096 and msm8996 that have KRYO processors, + * the CPU frequency subset and voltage value of each OPP varies + * based on the silicon variant in use. Qualcomm Process Voltage Scaling Tables + * defines the voltage and frequency value based on the msm-id in SMEM + * and speedbin blown in the efuse combination. + * The qcom-cpufreq-kryo driver reads the msm-id and efuse value from the SoC + * to provide the OPP framework with required information. + * This is used to determine the voltage and frequency value for each OPP of + * operating-points-v2 table when it is parsed by the OPP framework. + */ + +#include <linux/cpu.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/nvmem-consumer.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm_opp.h> +#include <linux/slab.h> +#include <linux/soc/qcom/smem.h> + +#define MSM_ID_SMEM 137 + +enum _msm_id { + MSM8996V3 = 0xF6ul, + APQ8096V3 = 0x123ul, + MSM8996SG = 0x131ul, + APQ8096SG = 0x138ul, +}; + +enum _msm8996_version { + MSM8996_V3, + MSM8996_SG, + NUM_OF_MSM8996_VERSIONS, +}; + +static enum _msm8996_version __init qcom_cpufreq_kryo_get_msm_id(void) +{ + size_t len; + u32 *msm_id; + enum _msm8996_version version; + + msm_id = qcom_smem_get(QCOM_SMEM_HOST_ANY, MSM_ID_SMEM, &len); + if (IS_ERR(msm_id)) + return NUM_OF_MSM8996_VERSIONS; + + /* The first 4 bytes are format, next to them is the actual msm-id */ + msm_id++; + + switch ((enum _msm_id)*msm_id) { + case MSM8996V3: + case APQ8096V3: + version = MSM8996_V3; + break; + case MSM8996SG: + case APQ8096SG: + version = MSM8996_SG; + break; + default: + version = NUM_OF_MSM8996_VERSIONS; + } + + return version; +} + +static int qcom_cpufreq_kryo_probe(struct platform_device *pdev) +{ + struct opp_table *opp_tables[NR_CPUS] = {0}; + struct platform_device *cpufreq_dt_pdev; + enum _msm8996_version msm8996_version; + struct nvmem_cell *speedbin_nvmem; + struct device_node *np; + struct device *cpu_dev; + unsigned cpu; + u8 *speedbin; + u32 versions; + size_t len; + int ret; + + cpu_dev = get_cpu_device(0); + if (NULL == cpu_dev) + ret = -ENODEV; + + msm8996_version = qcom_cpufreq_kryo_get_msm_id(); + if (NUM_OF_MSM8996_VERSIONS == msm8996_version) { + dev_err(cpu_dev, "Not Snapdragon 820/821!"); + return -ENODEV; + } + + np = dev_pm_opp_of_get_opp_desc_node(cpu_dev); + if (IS_ERR(np)) + return PTR_ERR(np); + + ret = of_device_is_compatible(np, "operating-points-v2-kryo-cpu"); + if (!ret) { + of_node_put(np); + return -ENOENT; + } + + speedbin_nvmem = of_nvmem_cell_get(np, NULL); + of_node_put(np); + if (IS_ERR(speedbin_nvmem)) { + dev_err(cpu_dev, "Could not get nvmem cell: %ld\n", + PTR_ERR(speedbin_nvmem)); + return PTR_ERR(speedbin_nvmem); + } + + speedbin = nvmem_cell_read(speedbin_nvmem, &len); + nvmem_cell_put(speedbin_nvmem); + + switch (msm8996_version) { + case MSM8996_V3: + versions = 1 << (unsigned int)(*speedbin); + break; + case MSM8996_SG: + versions = 1 << ((unsigned int)(*speedbin) + 4); + break; + default: + BUG(); + break; + } + + for_each_possible_cpu(cpu) { + cpu_dev = get_cpu_device(cpu); + if (NULL == cpu_dev) { + ret = -ENODEV; + goto free_opp; + } + + opp_tables[cpu] = dev_pm_opp_set_supported_hw(cpu_dev, + &versions, 1); + if (IS_ERR(opp_tables[cpu])) { + ret = PTR_ERR(opp_tables[cpu]); + dev_err(cpu_dev, "Failed to set supported hardware\n"); + goto free_opp; + } + } + + cpufreq_dt_pdev = platform_device_register_simple("cpufreq-dt", -1, + NULL, 0); + if (!IS_ERR(cpufreq_dt_pdev)) + return 0; + + ret = PTR_ERR(cpufreq_dt_pdev); + dev_err(cpu_dev, "Failed to register platform device\n"); + +free_opp: + for_each_possible_cpu(cpu) { + if (IS_ERR_OR_NULL(opp_tables[cpu])) + break; + dev_pm_opp_put_supported_hw(opp_tables[cpu]); + } + + return ret; +} + +static struct platform_driver qcom_cpufreq_kryo_driver = { + .probe = qcom_cpufreq_kryo_probe, + .driver = { + .name = "qcom-cpufreq-kryo", + }, +}; + +static const struct of_device_id qcom_cpufreq_kryo_match_list[] __initconst = { + { .compatible = "qcom,apq8096", }, + { .compatible = "qcom,msm8996", }, +}; + +/* + * Since the driver depends on smem and nvmem drivers, which may + * return EPROBE_DEFER, all the real activity is done in the probe, + * which may be defered as well. The init here is only registering + * the driver and the platform device. + */ +static int __init qcom_cpufreq_kryo_init(void) +{ + struct device_node *np = of_find_node_by_path("/"); + const struct of_device_id *match; + int ret; + + if (!np) + return -ENODEV; + + match = of_match_node(qcom_cpufreq_kryo_match_list, np); + of_node_put(np); + if (!match) + return -ENODEV; + + ret = platform_driver_register(&qcom_cpufreq_kryo_driver); + if (unlikely(ret < 0)) + return ret; + + ret = PTR_ERR_OR_ZERO(platform_device_register_simple( + "qcom-cpufreq-kryo", -1, NULL, 0)); + if (0 == ret) + return 0; + + platform_driver_unregister(&qcom_cpufreq_kryo_driver); + return ret; +} +module_init(qcom_cpufreq_kryo_init); + +MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Kryo CPUfreq driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/cpufreq/s3c2440-cpufreq.c b/drivers/cpufreq/s3c2440-cpufreq.c index d0d75b65ddd6..d2f67b7a20dd 100644 --- a/drivers/cpufreq/s3c2440-cpufreq.c +++ b/drivers/cpufreq/s3c2440-cpufreq.c @@ -143,7 +143,7 @@ static void s3c2440_cpufreq_setdivs(struct s3c_cpufreq_config *cfg) { unsigned long clkdiv, camdiv; - s3c_freq_dbg("%s: divsiors: h=%d, p=%d\n", __func__, + s3c_freq_dbg("%s: divisors: h=%d, p=%d\n", __func__, cfg->divs.h_divisor, cfg->divs.p_divisor); clkdiv = __raw_readl(S3C2410_CLKDIVN); diff --git a/drivers/cpufreq/speedstep-lib.c b/drivers/cpufreq/speedstep-lib.c index e3a9962ee410..cabb6f48eb77 100644 --- a/drivers/cpufreq/speedstep-lib.c +++ b/drivers/cpufreq/speedstep-lib.c @@ -252,7 +252,7 @@ EXPORT_SYMBOL_GPL(speedstep_get_frequency); *********************************************************************/ /* Keep in sync with the x86_cpu_id tables in the different modules */ -unsigned int speedstep_detect_processor(void) +enum speedstep_processor speedstep_detect_processor(void) { struct cpuinfo_x86 *c = &cpu_data(0); u32 ebx, msr_lo, msr_hi; diff --git a/drivers/cpufreq/tegra20-cpufreq.c b/drivers/cpufreq/tegra20-cpufreq.c index 2bd62845e9d5..05f57dcd5215 100644 --- a/drivers/cpufreq/tegra20-cpufreq.c +++ b/drivers/cpufreq/tegra20-cpufreq.c @@ -16,16 +16,13 @@ * */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/types.h> -#include <linux/sched.h> +#include <linux/clk.h> #include <linux/cpufreq.h> -#include <linux/delay.h> -#include <linux/init.h> #include <linux/err.h> -#include <linux/clk.h> -#include <linux/io.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/types.h> static struct cpufreq_frequency_table freq_table[] = { { .frequency = 216000 }, @@ -39,25 +36,27 @@ static struct cpufreq_frequency_table freq_table[] = { { .frequency = CPUFREQ_TABLE_END }, }; -#define NUM_CPUS 2 - -static struct clk *cpu_clk; -static struct clk *pll_x_clk; -static struct clk *pll_p_clk; -static struct clk *emc_clk; -static bool pll_x_prepared; +struct tegra20_cpufreq { + struct device *dev; + struct cpufreq_driver driver; + struct clk *cpu_clk; + struct clk *pll_x_clk; + struct clk *pll_p_clk; + bool pll_x_prepared; +}; static unsigned int tegra_get_intermediate(struct cpufreq_policy *policy, unsigned int index) { - unsigned int ifreq = clk_get_rate(pll_p_clk) / 1000; + struct tegra20_cpufreq *cpufreq = cpufreq_get_driver_data(); + unsigned int ifreq = clk_get_rate(cpufreq->pll_p_clk) / 1000; /* * Don't switch to intermediate freq if: * - we are already at it, i.e. policy->cur == ifreq * - index corresponds to ifreq */ - if ((freq_table[index].frequency == ifreq) || (policy->cur == ifreq)) + if (freq_table[index].frequency == ifreq || policy->cur == ifreq) return 0; return ifreq; @@ -66,6 +65,7 @@ static unsigned int tegra_get_intermediate(struct cpufreq_policy *policy, static int tegra_target_intermediate(struct cpufreq_policy *policy, unsigned int index) { + struct tegra20_cpufreq *cpufreq = cpufreq_get_driver_data(); int ret; /* @@ -78,47 +78,37 @@ static int tegra_target_intermediate(struct cpufreq_policy *policy, * Also, we wouldn't be using pll_x anymore and must not take extra * reference to it, as it can be disabled now to save some power. */ - clk_prepare_enable(pll_x_clk); + clk_prepare_enable(cpufreq->pll_x_clk); - ret = clk_set_parent(cpu_clk, pll_p_clk); + ret = clk_set_parent(cpufreq->cpu_clk, cpufreq->pll_p_clk); if (ret) - clk_disable_unprepare(pll_x_clk); + clk_disable_unprepare(cpufreq->pll_x_clk); else - pll_x_prepared = true; + cpufreq->pll_x_prepared = true; return ret; } static int tegra_target(struct cpufreq_policy *policy, unsigned int index) { + struct tegra20_cpufreq *cpufreq = cpufreq_get_driver_data(); unsigned long rate = freq_table[index].frequency; - unsigned int ifreq = clk_get_rate(pll_p_clk) / 1000; - int ret = 0; - - /* - * Vote on memory bus frequency based on cpu frequency - * This sets the minimum frequency, display or avp may request higher - */ - if (rate >= 816000) - clk_set_rate(emc_clk, 600000000); /* cpu 816 MHz, emc max */ - else if (rate >= 456000) - clk_set_rate(emc_clk, 300000000); /* cpu 456 MHz, emc 150Mhz */ - else - clk_set_rate(emc_clk, 100000000); /* emc 50Mhz */ + unsigned int ifreq = clk_get_rate(cpufreq->pll_p_clk) / 1000; + int ret; /* * target freq == pll_p, don't need to take extra reference to pll_x_clk * as it isn't used anymore. */ if (rate == ifreq) - return clk_set_parent(cpu_clk, pll_p_clk); + return clk_set_parent(cpufreq->cpu_clk, cpufreq->pll_p_clk); - ret = clk_set_rate(pll_x_clk, rate * 1000); + ret = clk_set_rate(cpufreq->pll_x_clk, rate * 1000); /* Restore to earlier frequency on error, i.e. pll_x */ if (ret) - pr_err("Failed to change pll_x to %lu\n", rate); + dev_err(cpufreq->dev, "Failed to change pll_x to %lu\n", rate); - ret = clk_set_parent(cpu_clk, pll_x_clk); + ret = clk_set_parent(cpufreq->cpu_clk, cpufreq->pll_x_clk); /* This shouldn't fail while changing or restoring */ WARN_ON(ret); @@ -126,9 +116,9 @@ static int tegra_target(struct cpufreq_policy *policy, unsigned int index) * Drop count to pll_x clock only if we switched to intermediate freq * earlier while transitioning to a target frequency. */ - if (pll_x_prepared) { - clk_disable_unprepare(pll_x_clk); - pll_x_prepared = false; + if (cpufreq->pll_x_prepared) { + clk_disable_unprepare(cpufreq->pll_x_clk); + cpufreq->pll_x_prepared = false; } return ret; @@ -136,81 +126,111 @@ static int tegra_target(struct cpufreq_policy *policy, unsigned int index) static int tegra_cpu_init(struct cpufreq_policy *policy) { + struct tegra20_cpufreq *cpufreq = cpufreq_get_driver_data(); int ret; - if (policy->cpu >= NUM_CPUS) - return -EINVAL; - - clk_prepare_enable(emc_clk); - clk_prepare_enable(cpu_clk); + clk_prepare_enable(cpufreq->cpu_clk); /* FIXME: what's the actual transition time? */ ret = cpufreq_generic_init(policy, freq_table, 300 * 1000); if (ret) { - clk_disable_unprepare(cpu_clk); - clk_disable_unprepare(emc_clk); + clk_disable_unprepare(cpufreq->cpu_clk); return ret; } - policy->clk = cpu_clk; + policy->clk = cpufreq->cpu_clk; policy->suspend_freq = freq_table[0].frequency; return 0; } static int tegra_cpu_exit(struct cpufreq_policy *policy) { - clk_disable_unprepare(cpu_clk); - clk_disable_unprepare(emc_clk); + struct tegra20_cpufreq *cpufreq = cpufreq_get_driver_data(); + + clk_disable_unprepare(cpufreq->cpu_clk); return 0; } -static struct cpufreq_driver tegra_cpufreq_driver = { - .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK, - .verify = cpufreq_generic_frequency_table_verify, - .get_intermediate = tegra_get_intermediate, - .target_intermediate = tegra_target_intermediate, - .target_index = tegra_target, - .get = cpufreq_generic_get, - .init = tegra_cpu_init, - .exit = tegra_cpu_exit, - .name = "tegra", - .attr = cpufreq_generic_attr, - .suspend = cpufreq_generic_suspend, -}; - -static int __init tegra_cpufreq_init(void) +static int tegra20_cpufreq_probe(struct platform_device *pdev) { - cpu_clk = clk_get_sys(NULL, "cclk"); - if (IS_ERR(cpu_clk)) - return PTR_ERR(cpu_clk); - - pll_x_clk = clk_get_sys(NULL, "pll_x"); - if (IS_ERR(pll_x_clk)) - return PTR_ERR(pll_x_clk); - - pll_p_clk = clk_get_sys(NULL, "pll_p"); - if (IS_ERR(pll_p_clk)) - return PTR_ERR(pll_p_clk); - - emc_clk = clk_get_sys("cpu", "emc"); - if (IS_ERR(emc_clk)) { - clk_put(cpu_clk); - return PTR_ERR(emc_clk); + struct tegra20_cpufreq *cpufreq; + int err; + + cpufreq = devm_kzalloc(&pdev->dev, sizeof(*cpufreq), GFP_KERNEL); + if (!cpufreq) + return -ENOMEM; + + cpufreq->cpu_clk = clk_get_sys(NULL, "cclk"); + if (IS_ERR(cpufreq->cpu_clk)) + return PTR_ERR(cpufreq->cpu_clk); + + cpufreq->pll_x_clk = clk_get_sys(NULL, "pll_x"); + if (IS_ERR(cpufreq->pll_x_clk)) { + err = PTR_ERR(cpufreq->pll_x_clk); + goto put_cpu; + } + + cpufreq->pll_p_clk = clk_get_sys(NULL, "pll_p"); + if (IS_ERR(cpufreq->pll_p_clk)) { + err = PTR_ERR(cpufreq->pll_p_clk); + goto put_pll_x; } - return cpufreq_register_driver(&tegra_cpufreq_driver); + cpufreq->dev = &pdev->dev; + cpufreq->driver.get = cpufreq_generic_get; + cpufreq->driver.attr = cpufreq_generic_attr; + cpufreq->driver.init = tegra_cpu_init; + cpufreq->driver.exit = tegra_cpu_exit; + cpufreq->driver.flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK; + cpufreq->driver.verify = cpufreq_generic_frequency_table_verify; + cpufreq->driver.suspend = cpufreq_generic_suspend; + cpufreq->driver.driver_data = cpufreq; + cpufreq->driver.target_index = tegra_target; + cpufreq->driver.get_intermediate = tegra_get_intermediate; + cpufreq->driver.target_intermediate = tegra_target_intermediate; + snprintf(cpufreq->driver.name, CPUFREQ_NAME_LEN, "tegra"); + + err = cpufreq_register_driver(&cpufreq->driver); + if (err) + goto put_pll_p; + + platform_set_drvdata(pdev, cpufreq); + + return 0; + +put_pll_p: + clk_put(cpufreq->pll_p_clk); +put_pll_x: + clk_put(cpufreq->pll_x_clk); +put_cpu: + clk_put(cpufreq->cpu_clk); + + return err; } -static void __exit tegra_cpufreq_exit(void) +static int tegra20_cpufreq_remove(struct platform_device *pdev) { - cpufreq_unregister_driver(&tegra_cpufreq_driver); - clk_put(emc_clk); - clk_put(cpu_clk); + struct tegra20_cpufreq *cpufreq = platform_get_drvdata(pdev); + + cpufreq_unregister_driver(&cpufreq->driver); + + clk_put(cpufreq->pll_p_clk); + clk_put(cpufreq->pll_x_clk); + clk_put(cpufreq->cpu_clk); + + return 0; } +static struct platform_driver tegra20_cpufreq_driver = { + .probe = tegra20_cpufreq_probe, + .remove = tegra20_cpufreq_remove, + .driver = { + .name = "tegra20-cpufreq", + }, +}; +module_platform_driver(tegra20_cpufreq_driver); +MODULE_ALIAS("platform:tegra20-cpufreq"); MODULE_AUTHOR("Colin Cross <ccross@android.com>"); -MODULE_DESCRIPTION("cpufreq driver for Nvidia Tegra2"); +MODULE_DESCRIPTION("NVIDIA Tegra20 cpufreq driver"); MODULE_LICENSE("GPL"); -module_init(tegra_cpufreq_init); -module_exit(tegra_cpufreq_exit); diff --git a/drivers/cpuidle/governor.c b/drivers/cpuidle/governor.c index 5d359aff3cc5..9fed1b829292 100644 --- a/drivers/cpuidle/governor.c +++ b/drivers/cpuidle/governor.c @@ -8,8 +8,10 @@ * This code is licenced under the GPL. */ -#include <linux/mutex.h> +#include <linux/cpu.h> #include <linux/cpuidle.h> +#include <linux/mutex.h> +#include <linux/pm_qos.h> #include "cpuidle.h" @@ -93,3 +95,16 @@ int cpuidle_register_governor(struct cpuidle_governor *gov) return ret; } + +/** + * cpuidle_governor_latency_req - Compute a latency constraint for CPU + * @cpu: Target CPU + */ +int cpuidle_governor_latency_req(unsigned int cpu) +{ + int global_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY); + struct device *device = get_cpu_device(cpu); + int device_req = dev_pm_qos_raw_read_value(device); + + return device_req < global_req ? device_req : global_req; +} diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c index b24883f85c99..704880a6612a 100644 --- a/drivers/cpuidle/governors/ladder.c +++ b/drivers/cpuidle/governors/ladder.c @@ -14,10 +14,8 @@ #include <linux/kernel.h> #include <linux/cpuidle.h> -#include <linux/pm_qos.h> #include <linux/jiffies.h> #include <linux/tick.h> -#include <linux/cpu.h> #include <asm/io.h> #include <linux/uaccess.h> @@ -69,16 +67,10 @@ static int ladder_select_state(struct cpuidle_driver *drv, struct cpuidle_device *dev, bool *dummy) { struct ladder_device *ldev = this_cpu_ptr(&ladder_devices); - struct device *device = get_cpu_device(dev->cpu); struct ladder_device_state *last_state; int last_residency, last_idx = ldev->last_state_idx; int first_idx = drv->states[0].flags & CPUIDLE_FLAG_POLLING ? 1 : 0; - int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY); - int resume_latency = dev_pm_qos_raw_read_value(device); - - if (resume_latency < latency_req && - resume_latency != PM_QOS_RESUME_LATENCY_NO_CONSTRAINT) - latency_req = resume_latency; + int latency_req = cpuidle_governor_latency_req(dev->cpu); /* Special case when user has set very strict latency requirement */ if (unlikely(latency_req == 0)) { diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index 1bfe03ceb236..1aef60d160eb 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -12,7 +12,6 @@ #include <linux/kernel.h> #include <linux/cpuidle.h> -#include <linux/pm_qos.h> #include <linux/time.h> #include <linux/ktime.h> #include <linux/hrtimer.h> @@ -21,7 +20,6 @@ #include <linux/sched/loadavg.h> #include <linux/sched/stat.h> #include <linux/math64.h> -#include <linux/cpu.h> /* * Please note when changing the tuning values: @@ -286,15 +284,13 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, bool *stop_tick) { struct menu_device *data = this_cpu_ptr(&menu_devices); - struct device *device = get_cpu_device(dev->cpu); - int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY); + int latency_req = cpuidle_governor_latency_req(dev->cpu); int i; int first_idx; int idx; unsigned int interactivity_req; unsigned int expected_interval; unsigned long nr_iowaiters, cpu_load; - int resume_latency = dev_pm_qos_raw_read_value(device); ktime_t delta_next; if (data->needs_update) { @@ -302,10 +298,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, data->needs_update = 0; } - if (resume_latency < latency_req && - resume_latency != PM_QOS_RESUME_LATENCY_NO_CONSTRAINT) - latency_req = resume_latency; - /* Special case when user has set very strict latency requirement */ if (unlikely(latency_req == 0)) { *stop_tick = false; diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index d1ea1a07cecb..43cccf6aff61 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -302,6 +302,7 @@ config CRYPTO_DEV_PPC4XX select CRYPTO_AEAD select CRYPTO_AES select CRYPTO_CCM + select CRYPTO_CTR select CRYPTO_GCM select CRYPTO_BLKCIPHER help @@ -419,7 +420,7 @@ config CRYPTO_DEV_EXYNOS_RNG config CRYPTO_DEV_S5P tristate "Support for Samsung S5PV210/Exynos crypto accelerator" depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST - depends on HAS_IOMEM && HAS_DMA + depends on HAS_IOMEM select CRYPTO_AES select CRYPTO_BLKCIPHER help @@ -466,7 +467,6 @@ endif # if CRYPTO_DEV_UX500 config CRYPTO_DEV_ATMEL_AUTHENC tristate "Support for Atmel IPSEC/SSL hw accelerator" - depends on HAS_DMA depends on ARCH_AT91 || COMPILE_TEST select CRYPTO_AUTHENC select CRYPTO_DEV_ATMEL_AES @@ -479,7 +479,6 @@ config CRYPTO_DEV_ATMEL_AUTHENC config CRYPTO_DEV_ATMEL_AES tristate "Support for Atmel AES hw accelerator" - depends on HAS_DMA depends on ARCH_AT91 || COMPILE_TEST select CRYPTO_AES select CRYPTO_AEAD @@ -494,7 +493,6 @@ config CRYPTO_DEV_ATMEL_AES config CRYPTO_DEV_ATMEL_TDES tristate "Support for Atmel DES/TDES hw accelerator" - depends on HAS_DMA depends on ARCH_AT91 || COMPILE_TEST select CRYPTO_DES select CRYPTO_BLKCIPHER @@ -508,7 +506,6 @@ config CRYPTO_DEV_ATMEL_TDES config CRYPTO_DEV_ATMEL_SHA tristate "Support for Atmel SHA hw accelerator" - depends on HAS_DMA depends on ARCH_AT91 || COMPILE_TEST select CRYPTO_HASH help @@ -574,7 +571,8 @@ config CRYPTO_DEV_CAVIUM_ZIP config CRYPTO_DEV_QCE tristate "Qualcomm crypto engine accelerator" - depends on (ARCH_QCOM || COMPILE_TEST) && HAS_DMA && HAS_IOMEM + depends on ARCH_QCOM || COMPILE_TEST + depends on HAS_IOMEM select CRYPTO_AES select CRYPTO_DES select CRYPTO_ECB @@ -598,7 +596,6 @@ source "drivers/crypto/vmx/Kconfig" config CRYPTO_DEV_IMGTEC_HASH tristate "Imagination Technologies hardware hash accelerator" depends on MIPS || COMPILE_TEST - depends on HAS_DMA select CRYPTO_MD5 select CRYPTO_SHA1 select CRYPTO_SHA256 @@ -650,7 +647,6 @@ config CRYPTO_DEV_ROCKCHIP config CRYPTO_DEV_MEDIATEK tristate "MediaTek's EIP97 Cryptographic Engine driver" - depends on HAS_DMA depends on (ARM && ARCH_MEDIATEK) || COMPILE_TEST select CRYPTO_AES select CRYPTO_AEAD @@ -688,9 +684,10 @@ source "drivers/crypto/stm32/Kconfig" config CRYPTO_DEV_SAFEXCEL tristate "Inside Secure's SafeXcel cryptographic engine driver" - depends on HAS_DMA && OF + depends on OF depends on (ARM64 && ARCH_MVEBU) || (COMPILE_TEST && 64BIT) select CRYPTO_AES + select CRYPTO_AUTHENC select CRYPTO_BLKCIPHER select CRYPTO_HASH select CRYPTO_HMAC @@ -706,7 +703,6 @@ config CRYPTO_DEV_SAFEXCEL config CRYPTO_DEV_ARTPEC6 tristate "Support for Axis ARTPEC-6/7 hardware crypto acceleration." depends on ARM && (ARCH_ARTPEC || COMPILE_TEST) - depends on HAS_DMA depends on OF select CRYPTO_AEAD select CRYPTO_AES diff --git a/drivers/crypto/amcc/crypto4xx_alg.c b/drivers/crypto/amcc/crypto4xx_alg.c index ea83d0bff0e9..f5c07498ea4f 100644 --- a/drivers/crypto/amcc/crypto4xx_alg.c +++ b/drivers/crypto/amcc/crypto4xx_alg.c @@ -31,6 +31,7 @@ #include <crypto/gcm.h> #include <crypto/sha.h> #include <crypto/ctr.h> +#include <crypto/skcipher.h> #include "crypto4xx_reg_def.h" #include "crypto4xx_core.h" #include "crypto4xx_sa.h" @@ -74,51 +75,57 @@ static void set_dynamic_sa_command_1(struct dynamic_sa_ctl *sa, u32 cm, sa->sa_command_1.bf.copy_hdr = cp_hdr; } -int crypto4xx_encrypt(struct ablkcipher_request *req) +static inline int crypto4xx_crypt(struct skcipher_request *req, + const unsigned int ivlen, bool decrypt) { - struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm); - unsigned int ivlen = crypto_ablkcipher_ivsize( - crypto_ablkcipher_reqtfm(req)); - __le32 iv[ivlen]; + struct crypto_skcipher *cipher = crypto_skcipher_reqtfm(req); + struct crypto4xx_ctx *ctx = crypto_skcipher_ctx(cipher); + __le32 iv[AES_IV_SIZE]; if (ivlen) - crypto4xx_memcpy_to_le32(iv, req->info, ivlen); + crypto4xx_memcpy_to_le32(iv, req->iv, ivlen); return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst, - req->nbytes, iv, ivlen, ctx->sa_out, ctx->sa_len, 0); + req->cryptlen, iv, ivlen, decrypt ? ctx->sa_in : ctx->sa_out, + ctx->sa_len, 0, NULL); } -int crypto4xx_decrypt(struct ablkcipher_request *req) +int crypto4xx_encrypt_noiv(struct skcipher_request *req) { - struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm); - unsigned int ivlen = crypto_ablkcipher_ivsize( - crypto_ablkcipher_reqtfm(req)); - __le32 iv[ivlen]; + return crypto4xx_crypt(req, 0, false); +} - if (ivlen) - crypto4xx_memcpy_to_le32(iv, req->info, ivlen); +int crypto4xx_encrypt_iv(struct skcipher_request *req) +{ + return crypto4xx_crypt(req, AES_IV_SIZE, false); +} - return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst, - req->nbytes, iv, ivlen, ctx->sa_in, ctx->sa_len, 0); +int crypto4xx_decrypt_noiv(struct skcipher_request *req) +{ + return crypto4xx_crypt(req, 0, true); +} + +int crypto4xx_decrypt_iv(struct skcipher_request *req) +{ + return crypto4xx_crypt(req, AES_IV_SIZE, true); } /** * AES Functions */ -static int crypto4xx_setkey_aes(struct crypto_ablkcipher *cipher, +static int crypto4xx_setkey_aes(struct crypto_skcipher *cipher, const u8 *key, unsigned int keylen, unsigned char cm, u8 fb) { - struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher); - struct crypto4xx_ctx *ctx = crypto_tfm_ctx(tfm); + struct crypto4xx_ctx *ctx = crypto_skcipher_ctx(cipher); struct dynamic_sa_ctl *sa; int rc; if (keylen != AES_KEYSIZE_256 && keylen != AES_KEYSIZE_192 && keylen != AES_KEYSIZE_128) { - crypto_ablkcipher_set_flags(cipher, + crypto_skcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN); return -EINVAL; } @@ -134,7 +141,8 @@ static int crypto4xx_setkey_aes(struct crypto_ablkcipher *cipher, /* Setup SA */ sa = ctx->sa_in; - set_dynamic_sa_command_0(sa, SA_NOT_SAVE_HASH, SA_NOT_SAVE_IV, + set_dynamic_sa_command_0(sa, SA_NOT_SAVE_HASH, (cm == CRYPTO_MODE_CBC ? + SA_SAVE_IV : SA_NOT_SAVE_IV), SA_LOAD_HASH_FROM_SA, SA_LOAD_IV_FROM_STATE, SA_NO_HEADER_PROC, SA_HASH_ALG_NULL, SA_CIPHER_ALG_AES, SA_PAD_TYPE_ZERO, @@ -158,39 +166,38 @@ static int crypto4xx_setkey_aes(struct crypto_ablkcipher *cipher, return 0; } -int crypto4xx_setkey_aes_cbc(struct crypto_ablkcipher *cipher, +int crypto4xx_setkey_aes_cbc(struct crypto_skcipher *cipher, const u8 *key, unsigned int keylen) { return crypto4xx_setkey_aes(cipher, key, keylen, CRYPTO_MODE_CBC, CRYPTO_FEEDBACK_MODE_NO_FB); } -int crypto4xx_setkey_aes_cfb(struct crypto_ablkcipher *cipher, +int crypto4xx_setkey_aes_cfb(struct crypto_skcipher *cipher, const u8 *key, unsigned int keylen) { return crypto4xx_setkey_aes(cipher, key, keylen, CRYPTO_MODE_CFB, CRYPTO_FEEDBACK_MODE_128BIT_CFB); } -int crypto4xx_setkey_aes_ecb(struct crypto_ablkcipher *cipher, +int crypto4xx_setkey_aes_ecb(struct crypto_skcipher *cipher, const u8 *key, unsigned int keylen) { return crypto4xx_setkey_aes(cipher, key, keylen, CRYPTO_MODE_ECB, CRYPTO_FEEDBACK_MODE_NO_FB); } -int crypto4xx_setkey_aes_ofb(struct crypto_ablkcipher *cipher, +int crypto4xx_setkey_aes_ofb(struct crypto_skcipher *cipher, const u8 *key, unsigned int keylen) { return crypto4xx_setkey_aes(cipher, key, keylen, CRYPTO_MODE_OFB, CRYPTO_FEEDBACK_MODE_64BIT_OFB); } -int crypto4xx_setkey_rfc3686(struct crypto_ablkcipher *cipher, +int crypto4xx_setkey_rfc3686(struct crypto_skcipher *cipher, const u8 *key, unsigned int keylen) { - struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher); - struct crypto4xx_ctx *ctx = crypto_tfm_ctx(tfm); + struct crypto4xx_ctx *ctx = crypto_skcipher_ctx(cipher); int rc; rc = crypto4xx_setkey_aes(cipher, key, keylen - CTR_RFC3686_NONCE_SIZE, @@ -204,35 +211,117 @@ int crypto4xx_setkey_rfc3686(struct crypto_ablkcipher *cipher, return 0; } -int crypto4xx_rfc3686_encrypt(struct ablkcipher_request *req) +int crypto4xx_rfc3686_encrypt(struct skcipher_request *req) { - struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm); + struct crypto_skcipher *cipher = crypto_skcipher_reqtfm(req); + struct crypto4xx_ctx *ctx = crypto_skcipher_ctx(cipher); __le32 iv[AES_IV_SIZE / 4] = { ctx->iv_nonce, - cpu_to_le32p((u32 *) req->info), - cpu_to_le32p((u32 *) (req->info + 4)), + cpu_to_le32p((u32 *) req->iv), + cpu_to_le32p((u32 *) (req->iv + 4)), cpu_to_le32(1) }; return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst, - req->nbytes, iv, AES_IV_SIZE, - ctx->sa_out, ctx->sa_len, 0); + req->cryptlen, iv, AES_IV_SIZE, + ctx->sa_out, ctx->sa_len, 0, NULL); } -int crypto4xx_rfc3686_decrypt(struct ablkcipher_request *req) +int crypto4xx_rfc3686_decrypt(struct skcipher_request *req) { - struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm); + struct crypto_skcipher *cipher = crypto_skcipher_reqtfm(req); + struct crypto4xx_ctx *ctx = crypto_skcipher_ctx(cipher); __le32 iv[AES_IV_SIZE / 4] = { ctx->iv_nonce, - cpu_to_le32p((u32 *) req->info), - cpu_to_le32p((u32 *) (req->info + 4)), + cpu_to_le32p((u32 *) req->iv), + cpu_to_le32p((u32 *) (req->iv + 4)), cpu_to_le32(1) }; return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst, - req->nbytes, iv, AES_IV_SIZE, - ctx->sa_out, ctx->sa_len, 0); + req->cryptlen, iv, AES_IV_SIZE, + ctx->sa_out, ctx->sa_len, 0, NULL); +} + +static int +crypto4xx_ctr_crypt(struct skcipher_request *req, bool encrypt) +{ + struct crypto_skcipher *cipher = crypto_skcipher_reqtfm(req); + struct crypto4xx_ctx *ctx = crypto_skcipher_ctx(cipher); + size_t iv_len = crypto_skcipher_ivsize(cipher); + unsigned int counter = be32_to_cpup((__be32 *)(req->iv + iv_len - 4)); + unsigned int nblks = ALIGN(req->cryptlen, AES_BLOCK_SIZE) / + AES_BLOCK_SIZE; + + /* + * The hardware uses only the last 32-bits as the counter while the + * kernel tests (aes_ctr_enc_tv_template[4] for example) expect that + * the whole IV is a counter. So fallback if the counter is going to + * overlow. + */ + if (counter + nblks < counter) { + struct skcipher_request *subreq = skcipher_request_ctx(req); + int ret; + + skcipher_request_set_tfm(subreq, ctx->sw_cipher.cipher); + skcipher_request_set_callback(subreq, req->base.flags, + NULL, NULL); + skcipher_request_set_crypt(subreq, req->src, req->dst, + req->cryptlen, req->iv); + ret = encrypt ? crypto_skcipher_encrypt(subreq) + : crypto_skcipher_decrypt(subreq); + skcipher_request_zero(subreq); + return ret; + } + + return encrypt ? crypto4xx_encrypt_iv(req) + : crypto4xx_decrypt_iv(req); +} + +static int crypto4xx_sk_setup_fallback(struct crypto4xx_ctx *ctx, + struct crypto_skcipher *cipher, + const u8 *key, + unsigned int keylen) +{ + int rc; + + crypto_skcipher_clear_flags(ctx->sw_cipher.cipher, + CRYPTO_TFM_REQ_MASK); + crypto_skcipher_set_flags(ctx->sw_cipher.cipher, + crypto_skcipher_get_flags(cipher) & CRYPTO_TFM_REQ_MASK); + rc = crypto_skcipher_setkey(ctx->sw_cipher.cipher, key, keylen); + crypto_skcipher_clear_flags(cipher, CRYPTO_TFM_RES_MASK); + crypto_skcipher_set_flags(cipher, + crypto_skcipher_get_flags(ctx->sw_cipher.cipher) & + CRYPTO_TFM_RES_MASK); + + return rc; +} + +int crypto4xx_setkey_aes_ctr(struct crypto_skcipher *cipher, + const u8 *key, unsigned int keylen) +{ + struct crypto4xx_ctx *ctx = crypto_skcipher_ctx(cipher); + int rc; + + rc = crypto4xx_sk_setup_fallback(ctx, cipher, key, keylen); + if (rc) + return rc; + + return crypto4xx_setkey_aes(cipher, key, keylen, + CRYPTO_MODE_CTR, CRYPTO_FEEDBACK_MODE_NO_FB); +} + +int crypto4xx_encrypt_ctr(struct skcipher_request *req) +{ + return crypto4xx_ctr_crypt(req, true); +} + +int crypto4xx_decrypt_ctr(struct skcipher_request *req) +{ + return crypto4xx_ctr_crypt(req, false); } static inline bool crypto4xx_aead_need_fallback(struct aead_request *req, + unsigned int len, bool is_ccm, bool decrypt) { struct crypto_aead *aead = crypto_aead_reqtfm(req); @@ -242,14 +331,14 @@ static inline bool crypto4xx_aead_need_fallback(struct aead_request *req, return true; /* - * hardware does not handle cases where cryptlen - * is less than a block + * hardware does not handle cases where plaintext + * is less than a block. */ - if (req->cryptlen < AES_BLOCK_SIZE) + if (len < AES_BLOCK_SIZE) return true; - /* assoc len needs to be a multiple of 4 */ - if (req->assoclen & 0x3) + /* assoc len needs to be a multiple of 4 and <= 1020 */ + if (req->assoclen & 0x3 || req->assoclen > 1020) return true; /* CCM supports only counter field length of 2 and 4 bytes */ @@ -262,13 +351,7 @@ static inline bool crypto4xx_aead_need_fallback(struct aead_request *req, static int crypto4xx_aead_fallback(struct aead_request *req, struct crypto4xx_ctx *ctx, bool do_decrypt) { - char aead_req_data[sizeof(struct aead_request) + - crypto_aead_reqsize(ctx->sw_cipher.aead)] - __aligned(__alignof__(struct aead_request)); - - struct aead_request *subreq = (void *) aead_req_data; - - memset(subreq, 0, sizeof(aead_req_data)); + struct aead_request *subreq = aead_request_ctx(req); aead_request_set_tfm(subreq, ctx->sw_cipher.aead); aead_request_set_callback(subreq, req->base.flags, @@ -280,10 +363,10 @@ static int crypto4xx_aead_fallback(struct aead_request *req, crypto_aead_encrypt(subreq); } -static int crypto4xx_setup_fallback(struct crypto4xx_ctx *ctx, - struct crypto_aead *cipher, - const u8 *key, - unsigned int keylen) +static int crypto4xx_aead_setup_fallback(struct crypto4xx_ctx *ctx, + struct crypto_aead *cipher, + const u8 *key, + unsigned int keylen) { int rc; @@ -311,7 +394,7 @@ int crypto4xx_setkey_aes_ccm(struct crypto_aead *cipher, const u8 *key, struct dynamic_sa_ctl *sa; int rc = 0; - rc = crypto4xx_setup_fallback(ctx, cipher, key, keylen); + rc = crypto4xx_aead_setup_fallback(ctx, cipher, key, keylen); if (rc) return rc; @@ -366,19 +449,20 @@ int crypto4xx_setkey_aes_ccm(struct crypto_aead *cipher, const u8 *key, static int crypto4xx_crypt_aes_ccm(struct aead_request *req, bool decrypt) { struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm); + struct crypto4xx_aead_reqctx *rctx = aead_request_ctx(req); struct crypto_aead *aead = crypto_aead_reqtfm(req); - unsigned int len = req->cryptlen; __le32 iv[16]; - u32 tmp_sa[ctx->sa_len * 4]; + u32 tmp_sa[SA_AES128_CCM_LEN + 4]; struct dynamic_sa_ctl *sa = (struct dynamic_sa_ctl *)tmp_sa; - - if (crypto4xx_aead_need_fallback(req, true, decrypt)) - return crypto4xx_aead_fallback(req, ctx, decrypt); + unsigned int len = req->cryptlen; if (decrypt) len -= crypto_aead_authsize(aead); - memcpy(tmp_sa, decrypt ? ctx->sa_in : ctx->sa_out, sizeof(tmp_sa)); + if (crypto4xx_aead_need_fallback(req, len, true, decrypt)) + return crypto4xx_aead_fallback(req, ctx, decrypt); + + memcpy(tmp_sa, decrypt ? ctx->sa_in : ctx->sa_out, ctx->sa_len * 4); sa->sa_command_0.bf.digest_len = crypto_aead_authsize(aead) >> 2; if (req->iv[0] == 1) { @@ -391,7 +475,7 @@ static int crypto4xx_crypt_aes_ccm(struct aead_request *req, bool decrypt) return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst, len, iv, sizeof(iv), - sa, ctx->sa_len, req->assoclen); + sa, ctx->sa_len, req->assoclen, rctx->dst); } int crypto4xx_encrypt_aes_ccm(struct aead_request *req) @@ -470,7 +554,7 @@ int crypto4xx_setkey_aes_gcm(struct crypto_aead *cipher, return -EINVAL; } - rc = crypto4xx_setup_fallback(ctx, cipher, key, keylen); + rc = crypto4xx_aead_setup_fallback(ctx, cipher, key, keylen); if (rc) return rc; @@ -523,22 +607,23 @@ static inline int crypto4xx_crypt_aes_gcm(struct aead_request *req, bool decrypt) { struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm); - unsigned int len = req->cryptlen; + struct crypto4xx_aead_reqctx *rctx = aead_request_ctx(req); __le32 iv[4]; + unsigned int len = req->cryptlen; + + if (decrypt) + len -= crypto_aead_authsize(crypto_aead_reqtfm(req)); - if (crypto4xx_aead_need_fallback(req, false, decrypt)) + if (crypto4xx_aead_need_fallback(req, len, false, decrypt)) return crypto4xx_aead_fallback(req, ctx, decrypt); crypto4xx_memcpy_to_le32(iv, req->iv, GCM_AES_IV_SIZE); iv[3] = cpu_to_le32(1); - if (decrypt) - len -= crypto_aead_authsize(crypto_aead_reqtfm(req)); - return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst, len, iv, sizeof(iv), decrypt ? ctx->sa_in : ctx->sa_out, - ctx->sa_len, req->assoclen); + ctx->sa_len, req->assoclen, rctx->dst); } int crypto4xx_encrypt_aes_gcm(struct aead_request *req) @@ -623,7 +708,7 @@ int crypto4xx_hash_update(struct ahash_request *req) return crypto4xx_build_pd(&req->base, ctx, req->src, &dst, req->nbytes, NULL, 0, ctx->sa_in, - ctx->sa_len, 0); + ctx->sa_len, 0, NULL); } int crypto4xx_hash_final(struct ahash_request *req) @@ -642,7 +727,7 @@ int crypto4xx_hash_digest(struct ahash_request *req) return crypto4xx_build_pd(&req->base, ctx, req->src, &dst, req->nbytes, NULL, 0, ctx->sa_in, - ctx->sa_len, 0); + ctx->sa_len, 0, NULL); } /** diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c index 76f459ad2821..9cb234c72549 100644 --- a/drivers/crypto/amcc/crypto4xx_core.c +++ b/drivers/crypto/amcc/crypto4xx_core.c @@ -41,6 +41,7 @@ #include <crypto/gcm.h> #include <crypto/sha.h> #include <crypto/scatterwalk.h> +#include <crypto/skcipher.h> #include <crypto/internal/aead.h> #include <crypto/internal/skcipher.h> #include "crypto4xx_reg_def.h" @@ -526,31 +527,38 @@ static void crypto4xx_ret_sg_desc(struct crypto4xx_device *dev, } } -static void crypto4xx_ablkcipher_done(struct crypto4xx_device *dev, +static void crypto4xx_cipher_done(struct crypto4xx_device *dev, struct pd_uinfo *pd_uinfo, struct ce_pd *pd) { - struct crypto4xx_ctx *ctx; - struct ablkcipher_request *ablk_req; + struct skcipher_request *req; struct scatterlist *dst; dma_addr_t addr; - ablk_req = ablkcipher_request_cast(pd_uinfo->async_req); - ctx = crypto_tfm_ctx(ablk_req->base.tfm); + req = skcipher_request_cast(pd_uinfo->async_req); if (pd_uinfo->using_sd) { - crypto4xx_copy_pkt_to_dst(dev, pd, pd_uinfo, ablk_req->nbytes, - ablk_req->dst); + crypto4xx_copy_pkt_to_dst(dev, pd, pd_uinfo, + req->cryptlen, req->dst); } else { dst = pd_uinfo->dest_va; addr = dma_map_page(dev->core_dev->device, sg_page(dst), dst->offset, dst->length, DMA_FROM_DEVICE); } + + if (pd_uinfo->sa_va->sa_command_0.bf.save_iv == SA_SAVE_IV) { + struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); + + crypto4xx_memcpy_from_le32((u32 *)req->iv, + pd_uinfo->sr_va->save_iv, + crypto_skcipher_ivsize(skcipher)); + } + crypto4xx_ret_sg_desc(dev, pd_uinfo); if (pd_uinfo->state & PD_ENTRY_BUSY) - ablkcipher_request_complete(ablk_req, -EINPROGRESS); - ablkcipher_request_complete(ablk_req, 0); + skcipher_request_complete(req, -EINPROGRESS); + skcipher_request_complete(req, 0); } static void crypto4xx_ahash_done(struct crypto4xx_device *dev, @@ -580,7 +588,7 @@ static void crypto4xx_aead_done(struct crypto4xx_device *dev, struct scatterlist *dst = pd_uinfo->dest_va; size_t cp_len = crypto_aead_authsize( crypto_aead_reqtfm(aead_req)); - u32 icv[cp_len]; + u32 icv[AES_BLOCK_SIZE]; int err = 0; if (pd_uinfo->using_sd) { @@ -595,7 +603,7 @@ static void crypto4xx_aead_done(struct crypto4xx_device *dev, if (pd_uinfo->sa_va->sa_command_0.bf.dir == DIR_OUTBOUND) { /* append icv at the end */ crypto4xx_memcpy_from_le32(icv, pd_uinfo->sr_va->save_digest, - cp_len); + sizeof(icv)); scatterwalk_map_and_copy(icv, dst, aead_req->cryptlen, cp_len, 1); @@ -605,7 +613,7 @@ static void crypto4xx_aead_done(struct crypto4xx_device *dev, aead_req->assoclen + aead_req->cryptlen - cp_len, cp_len, 0); - crypto4xx_memcpy_from_le32(icv, icv, cp_len); + crypto4xx_memcpy_from_le32(icv, icv, sizeof(icv)); if (crypto_memneq(icv, pd_uinfo->sr_va->save_digest, cp_len)) err = -EBADMSG; @@ -641,8 +649,8 @@ static void crypto4xx_pd_done(struct crypto4xx_device *dev, u32 idx) struct pd_uinfo *pd_uinfo = &dev->pdr_uinfo[idx]; switch (crypto_tfm_alg_type(pd_uinfo->async_req->tfm)) { - case CRYPTO_ALG_TYPE_ABLKCIPHER: - crypto4xx_ablkcipher_done(dev, pd_uinfo, pd); + case CRYPTO_ALG_TYPE_SKCIPHER: + crypto4xx_cipher_done(dev, pd_uinfo, pd); break; case CRYPTO_ALG_TYPE_AEAD: crypto4xx_aead_done(dev, pd_uinfo, pd); @@ -687,9 +695,9 @@ int crypto4xx_build_pd(struct crypto_async_request *req, const __le32 *iv, const u32 iv_len, const struct dynamic_sa_ctl *req_sa, const unsigned int sa_len, - const unsigned int assoclen) + const unsigned int assoclen, + struct scatterlist *_dst) { - struct scatterlist _dst[2]; struct crypto4xx_device *dev = ctx->dev; struct dynamic_sa_ctl *sa; struct ce_gd *gd; @@ -936,15 +944,27 @@ static void crypto4xx_ctx_init(struct crypto4xx_alg *amcc_alg, ctx->sa_len = 0; } -static int crypto4xx_ablk_init(struct crypto_tfm *tfm) +static int crypto4xx_sk_init(struct crypto_skcipher *sk) { - struct crypto_alg *alg = tfm->__crt_alg; + struct skcipher_alg *alg = crypto_skcipher_alg(sk); struct crypto4xx_alg *amcc_alg; - struct crypto4xx_ctx *ctx = crypto_tfm_ctx(tfm); + struct crypto4xx_ctx *ctx = crypto_skcipher_ctx(sk); + + if (alg->base.cra_flags & CRYPTO_ALG_NEED_FALLBACK) { + ctx->sw_cipher.cipher = + crypto_alloc_skcipher(alg->base.cra_name, 0, + CRYPTO_ALG_NEED_FALLBACK | + CRYPTO_ALG_ASYNC); + if (IS_ERR(ctx->sw_cipher.cipher)) + return PTR_ERR(ctx->sw_cipher.cipher); + + crypto_skcipher_set_reqsize(sk, + sizeof(struct skcipher_request) + 32 + + crypto_skcipher_reqsize(ctx->sw_cipher.cipher)); + } amcc_alg = container_of(alg, struct crypto4xx_alg, alg.u.cipher); crypto4xx_ctx_init(amcc_alg, ctx); - tfm->crt_ablkcipher.reqsize = sizeof(struct crypto4xx_ctx); return 0; } @@ -953,9 +973,13 @@ static void crypto4xx_common_exit(struct crypto4xx_ctx *ctx) crypto4xx_free_sa(ctx); } -static void crypto4xx_ablk_exit(struct crypto_tfm *tfm) +static void crypto4xx_sk_exit(struct crypto_skcipher *sk) { - crypto4xx_common_exit(crypto_tfm_ctx(tfm)); + struct crypto4xx_ctx *ctx = crypto_skcipher_ctx(sk); + + crypto4xx_common_exit(ctx); + if (ctx->sw_cipher.cipher) + crypto_free_skcipher(ctx->sw_cipher.cipher); } static int crypto4xx_aead_init(struct crypto_aead *tfm) @@ -972,9 +996,9 @@ static int crypto4xx_aead_init(struct crypto_aead *tfm) amcc_alg = container_of(alg, struct crypto4xx_alg, alg.u.aead); crypto4xx_ctx_init(amcc_alg, ctx); - crypto_aead_set_reqsize(tfm, sizeof(struct aead_request) + - max(sizeof(struct crypto4xx_ctx), 32 + - crypto_aead_reqsize(ctx->sw_cipher.aead))); + crypto_aead_set_reqsize(tfm, max(sizeof(struct aead_request) + 32 + + crypto_aead_reqsize(ctx->sw_cipher.aead), + sizeof(struct crypto4xx_aead_reqctx))); return 0; } @@ -1012,7 +1036,7 @@ static int crypto4xx_register_alg(struct crypto4xx_device *sec_dev, break; default: - rc = crypto_register_alg(&alg->alg.u.cipher); + rc = crypto_register_skcipher(&alg->alg.u.cipher); break; } @@ -1041,7 +1065,7 @@ static void crypto4xx_unregister_alg(struct crypto4xx_device *sec_dev) break; default: - crypto_unregister_alg(&alg->alg.u.cipher); + crypto_unregister_skcipher(&alg->alg.u.cipher); } kfree(alg); } @@ -1103,126 +1127,131 @@ static irqreturn_t crypto4xx_ce_interrupt_handler_revb(int irq, void *data) */ static struct crypto4xx_alg_common crypto4xx_alg[] = { /* Crypto AES modes */ - { .type = CRYPTO_ALG_TYPE_ABLKCIPHER, .u.cipher = { - .cra_name = "cbc(aes)", - .cra_driver_name = "cbc-aes-ppc4xx", - .cra_priority = CRYPTO4XX_CRYPTO_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_KERN_DRIVER_ONLY, - .cra_blocksize = AES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct crypto4xx_ctx), - .cra_type = &crypto_ablkcipher_type, - .cra_init = crypto4xx_ablk_init, - .cra_exit = crypto4xx_ablk_exit, - .cra_module = THIS_MODULE, - .cra_u = { - .ablkcipher = { - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .ivsize = AES_IV_SIZE, - .setkey = crypto4xx_setkey_aes_cbc, - .encrypt = crypto4xx_encrypt, - .decrypt = crypto4xx_decrypt, - } - } - }}, - { .type = CRYPTO_ALG_TYPE_ABLKCIPHER, .u.cipher = { - .cra_name = "cfb(aes)", - .cra_driver_name = "cfb-aes-ppc4xx", - .cra_priority = CRYPTO4XX_CRYPTO_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_KERN_DRIVER_ONLY, - .cra_blocksize = AES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct crypto4xx_ctx), - .cra_type = &crypto_ablkcipher_type, - .cra_init = crypto4xx_ablk_init, - .cra_exit = crypto4xx_ablk_exit, - .cra_module = THIS_MODULE, - .cra_u = { - .ablkcipher = { - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .ivsize = AES_IV_SIZE, - .setkey = crypto4xx_setkey_aes_cfb, - .encrypt = crypto4xx_encrypt, - .decrypt = crypto4xx_decrypt, - } - } + { .type = CRYPTO_ALG_TYPE_SKCIPHER, .u.cipher = { + .base = { + .cra_name = "cbc(aes)", + .cra_driver_name = "cbc-aes-ppc4xx", + .cra_priority = CRYPTO4XX_CRYPTO_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_SKCIPHER | + CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct crypto4xx_ctx), + .cra_module = THIS_MODULE, + }, + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_IV_SIZE, + .setkey = crypto4xx_setkey_aes_cbc, + .encrypt = crypto4xx_encrypt_iv, + .decrypt = crypto4xx_decrypt_iv, + .init = crypto4xx_sk_init, + .exit = crypto4xx_sk_exit, } }, - { .type = CRYPTO_ALG_TYPE_ABLKCIPHER, .u.cipher = { - .cra_name = "rfc3686(ctr(aes))", - .cra_driver_name = "rfc3686-ctr-aes-ppc4xx", - .cra_priority = CRYPTO4XX_CRYPTO_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_KERN_DRIVER_ONLY, - .cra_blocksize = AES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct crypto4xx_ctx), - .cra_type = &crypto_ablkcipher_type, - .cra_init = crypto4xx_ablk_init, - .cra_exit = crypto4xx_ablk_exit, - .cra_module = THIS_MODULE, - .cra_u = { - .ablkcipher = { - .min_keysize = AES_MIN_KEY_SIZE + - CTR_RFC3686_NONCE_SIZE, - .max_keysize = AES_MAX_KEY_SIZE + - CTR_RFC3686_NONCE_SIZE, - .ivsize = CTR_RFC3686_IV_SIZE, - .setkey = crypto4xx_setkey_rfc3686, - .encrypt = crypto4xx_rfc3686_encrypt, - .decrypt = crypto4xx_rfc3686_decrypt, - } - } + { .type = CRYPTO_ALG_TYPE_SKCIPHER, .u.cipher = { + .base = { + .cra_name = "cfb(aes)", + .cra_driver_name = "cfb-aes-ppc4xx", + .cra_priority = CRYPTO4XX_CRYPTO_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_SKCIPHER | + CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct crypto4xx_ctx), + .cra_module = THIS_MODULE, + }, + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_IV_SIZE, + .setkey = crypto4xx_setkey_aes_cfb, + .encrypt = crypto4xx_encrypt_iv, + .decrypt = crypto4xx_decrypt_iv, + .init = crypto4xx_sk_init, + .exit = crypto4xx_sk_exit, } }, - { .type = CRYPTO_ALG_TYPE_ABLKCIPHER, .u.cipher = { - .cra_name = "ecb(aes)", - .cra_driver_name = "ecb-aes-ppc4xx", - .cra_priority = CRYPTO4XX_CRYPTO_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_KERN_DRIVER_ONLY, - .cra_blocksize = AES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct crypto4xx_ctx), - .cra_type = &crypto_ablkcipher_type, - .cra_init = crypto4xx_ablk_init, - .cra_exit = crypto4xx_ablk_exit, - .cra_module = THIS_MODULE, - .cra_u = { - .ablkcipher = { - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .setkey = crypto4xx_setkey_aes_ecb, - .encrypt = crypto4xx_encrypt, - .decrypt = crypto4xx_decrypt, - } - } + { .type = CRYPTO_ALG_TYPE_SKCIPHER, .u.cipher = { + .base = { + .cra_name = "ctr(aes)", + .cra_driver_name = "ctr-aes-ppc4xx", + .cra_priority = CRYPTO4XX_CRYPTO_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_SKCIPHER | + CRYPTO_ALG_NEED_FALLBACK | + CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct crypto4xx_ctx), + .cra_module = THIS_MODULE, + }, + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_IV_SIZE, + .setkey = crypto4xx_setkey_aes_ctr, + .encrypt = crypto4xx_encrypt_ctr, + .decrypt = crypto4xx_decrypt_ctr, + .init = crypto4xx_sk_init, + .exit = crypto4xx_sk_exit, } }, - { .type = CRYPTO_ALG_TYPE_ABLKCIPHER, .u.cipher = { - .cra_name = "ofb(aes)", - .cra_driver_name = "ofb-aes-ppc4xx", - .cra_priority = CRYPTO4XX_CRYPTO_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_KERN_DRIVER_ONLY, - .cra_blocksize = AES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct crypto4xx_ctx), - .cra_type = &crypto_ablkcipher_type, - .cra_init = crypto4xx_ablk_init, - .cra_exit = crypto4xx_ablk_exit, - .cra_module = THIS_MODULE, - .cra_u = { - .ablkcipher = { - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .ivsize = AES_IV_SIZE, - .setkey = crypto4xx_setkey_aes_ofb, - .encrypt = crypto4xx_encrypt, - .decrypt = crypto4xx_decrypt, - } - } + { .type = CRYPTO_ALG_TYPE_SKCIPHER, .u.cipher = { + .base = { + .cra_name = "rfc3686(ctr(aes))", + .cra_driver_name = "rfc3686-ctr-aes-ppc4xx", + .cra_priority = CRYPTO4XX_CRYPTO_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_SKCIPHER | + CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct crypto4xx_ctx), + .cra_module = THIS_MODULE, + }, + .min_keysize = AES_MIN_KEY_SIZE + CTR_RFC3686_NONCE_SIZE, + .max_keysize = AES_MAX_KEY_SIZE + CTR_RFC3686_NONCE_SIZE, + .ivsize = CTR_RFC3686_IV_SIZE, + .setkey = crypto4xx_setkey_rfc3686, + .encrypt = crypto4xx_rfc3686_encrypt, + .decrypt = crypto4xx_rfc3686_decrypt, + .init = crypto4xx_sk_init, + .exit = crypto4xx_sk_exit, + } }, + { .type = CRYPTO_ALG_TYPE_SKCIPHER, .u.cipher = { + .base = { + .cra_name = "ecb(aes)", + .cra_driver_name = "ecb-aes-ppc4xx", + .cra_priority = CRYPTO4XX_CRYPTO_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_SKCIPHER | + CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct crypto4xx_ctx), + .cra_module = THIS_MODULE, + }, + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .setkey = crypto4xx_setkey_aes_ecb, + .encrypt = crypto4xx_encrypt_noiv, + .decrypt = crypto4xx_decrypt_noiv, + .init = crypto4xx_sk_init, + .exit = crypto4xx_sk_exit, + } }, + { .type = CRYPTO_ALG_TYPE_SKCIPHER, .u.cipher = { + .base = { + .cra_name = "ofb(aes)", + .cra_driver_name = "ofb-aes-ppc4xx", + .cra_priority = CRYPTO4XX_CRYPTO_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_SKCIPHER | + CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct crypto4xx_ctx), + .cra_module = THIS_MODULE, + }, + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_IV_SIZE, + .setkey = crypto4xx_setkey_aes_ofb, + .encrypt = crypto4xx_encrypt_iv, + .decrypt = crypto4xx_decrypt_iv, + .init = crypto4xx_sk_init, + .exit = crypto4xx_sk_exit, } }, /* AEAD */ diff --git a/drivers/crypto/amcc/crypto4xx_core.h b/drivers/crypto/amcc/crypto4xx_core.h index 23b726da6534..e2ca56722f07 100644 --- a/drivers/crypto/amcc/crypto4xx_core.h +++ b/drivers/crypto/amcc/crypto4xx_core.h @@ -25,6 +25,7 @@ #include <linux/ratelimit.h> #include <crypto/internal/hash.h> #include <crypto/internal/aead.h> +#include <crypto/internal/skcipher.h> #include "crypto4xx_reg_def.h" #include "crypto4xx_sa.h" @@ -127,14 +128,19 @@ struct crypto4xx_ctx { __le32 iv_nonce; u32 sa_len; union { + struct crypto_skcipher *cipher; struct crypto_aead *aead; } sw_cipher; }; +struct crypto4xx_aead_reqctx { + struct scatterlist dst[2]; +}; + struct crypto4xx_alg_common { u32 type; union { - struct crypto_alg cipher; + struct skcipher_alg cipher; struct ahash_alg hash; struct aead_alg aead; } u; @@ -157,21 +163,28 @@ int crypto4xx_build_pd(struct crypto_async_request *req, const __le32 *iv, const u32 iv_len, const struct dynamic_sa_ctl *sa, const unsigned int sa_len, - const unsigned int assoclen); -int crypto4xx_setkey_aes_cbc(struct crypto_ablkcipher *cipher, + const unsigned int assoclen, + struct scatterlist *dst_tmp); +int crypto4xx_setkey_aes_cbc(struct crypto_skcipher *cipher, + const u8 *key, unsigned int keylen); +int crypto4xx_setkey_aes_cfb(struct crypto_skcipher *cipher, const u8 *key, unsigned int keylen); -int crypto4xx_setkey_aes_cfb(struct crypto_ablkcipher *cipher, +int crypto4xx_setkey_aes_ctr(struct crypto_skcipher *cipher, const u8 *key, unsigned int keylen); -int crypto4xx_setkey_aes_ecb(struct crypto_ablkcipher *cipher, +int crypto4xx_setkey_aes_ecb(struct crypto_skcipher *cipher, const u8 *key, unsigned int keylen); -int crypto4xx_setkey_aes_ofb(struct crypto_ablkcipher *cipher, +int crypto4xx_setkey_aes_ofb(struct crypto_skcipher *cipher, const u8 *key, unsigned int keylen); -int crypto4xx_setkey_rfc3686(struct crypto_ablkcipher *cipher, +int crypto4xx_setkey_rfc3686(struct crypto_skcipher *cipher, const u8 *key, unsigned int keylen); -int crypto4xx_encrypt(struct ablkcipher_request *req); -int crypto4xx_decrypt(struct ablkcipher_request *req); -int crypto4xx_rfc3686_encrypt(struct ablkcipher_request *req); -int crypto4xx_rfc3686_decrypt(struct ablkcipher_request *req); +int crypto4xx_encrypt_ctr(struct skcipher_request *req); +int crypto4xx_decrypt_ctr(struct skcipher_request *req); +int crypto4xx_encrypt_iv(struct skcipher_request *req); +int crypto4xx_decrypt_iv(struct skcipher_request *req); +int crypto4xx_encrypt_noiv(struct skcipher_request *req); +int crypto4xx_decrypt_noiv(struct skcipher_request *req); +int crypto4xx_rfc3686_encrypt(struct skcipher_request *req); +int crypto4xx_rfc3686_decrypt(struct skcipher_request *req); int crypto4xx_sha1_alg_init(struct crypto_tfm *tfm); int crypto4xx_hash_digest(struct ahash_request *req); int crypto4xx_hash_final(struct ahash_request *req); diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index 7207a535942d..d67667970f7e 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -769,15 +769,18 @@ struct aead_edesc { * @src_nents: number of segments in input s/w scatterlist * @dst_nents: number of segments in output s/w scatterlist * @iv_dma: dma address of iv for checking continuity and link table + * @iv_dir: DMA mapping direction for IV * @sec4_sg_bytes: length of dma mapped sec4_sg space * @sec4_sg_dma: bus physical mapped address of h/w link table * @sec4_sg: pointer to h/w link table * @hw_desc: the h/w job descriptor followed by any referenced link tables + * and IV */ struct ablkcipher_edesc { int src_nents; int dst_nents; dma_addr_t iv_dma; + enum dma_data_direction iv_dir; int sec4_sg_bytes; dma_addr_t sec4_sg_dma; struct sec4_sg_entry *sec4_sg; @@ -787,7 +790,8 @@ struct ablkcipher_edesc { static void caam_unmap(struct device *dev, struct scatterlist *src, struct scatterlist *dst, int src_nents, int dst_nents, - dma_addr_t iv_dma, int ivsize, dma_addr_t sec4_sg_dma, + dma_addr_t iv_dma, int ivsize, + enum dma_data_direction iv_dir, dma_addr_t sec4_sg_dma, int sec4_sg_bytes) { if (dst != src) { @@ -799,7 +803,7 @@ static void caam_unmap(struct device *dev, struct scatterlist *src, } if (iv_dma) - dma_unmap_single(dev, iv_dma, ivsize, DMA_TO_DEVICE); + dma_unmap_single(dev, iv_dma, ivsize, iv_dir); if (sec4_sg_bytes) dma_unmap_single(dev, sec4_sg_dma, sec4_sg_bytes, DMA_TO_DEVICE); @@ -810,7 +814,7 @@ static void aead_unmap(struct device *dev, struct aead_request *req) { caam_unmap(dev, req->src, req->dst, - edesc->src_nents, edesc->dst_nents, 0, 0, + edesc->src_nents, edesc->dst_nents, 0, 0, DMA_NONE, edesc->sec4_sg_dma, edesc->sec4_sg_bytes); } @@ -823,7 +827,7 @@ static void ablkcipher_unmap(struct device *dev, caam_unmap(dev, req->src, req->dst, edesc->src_nents, edesc->dst_nents, - edesc->iv_dma, ivsize, + edesc->iv_dma, ivsize, edesc->iv_dir, edesc->sec4_sg_dma, edesc->sec4_sg_bytes); } @@ -912,6 +916,18 @@ static void ablkcipher_encrypt_done(struct device *jrdev, u32 *desc, u32 err, scatterwalk_map_and_copy(req->info, req->dst, req->nbytes - ivsize, ivsize, 0); + /* In case initial IV was generated, copy it in GIVCIPHER request */ + if (edesc->iv_dir == DMA_FROM_DEVICE) { + u8 *iv; + struct skcipher_givcrypt_request *greq; + + greq = container_of(req, struct skcipher_givcrypt_request, + creq); + iv = (u8 *)edesc->hw_desc + desc_bytes(edesc->hw_desc) + + edesc->sec4_sg_bytes; + memcpy(greq->giv, iv, ivsize); + } + kfree(edesc); ablkcipher_request_complete(req, err); @@ -922,10 +938,10 @@ static void ablkcipher_decrypt_done(struct device *jrdev, u32 *desc, u32 err, { struct ablkcipher_request *req = context; struct ablkcipher_edesc *edesc; +#ifdef DEBUG struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); int ivsize = crypto_ablkcipher_ivsize(ablkcipher); -#ifdef DEBUG dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); #endif @@ -943,14 +959,6 @@ static void ablkcipher_decrypt_done(struct device *jrdev, u32 *desc, u32 err, edesc->dst_nents > 1 ? 100 : req->nbytes, 1); ablkcipher_unmap(jrdev, edesc, req); - - /* - * The crypto API expects us to set the IV (req->info) to the last - * ciphertext block. - */ - scatterwalk_map_and_copy(req->info, req->src, req->nbytes - ivsize, - ivsize, 0); - kfree(edesc); ablkcipher_request_complete(req, err); @@ -1099,15 +1107,14 @@ static void init_authenc_job(struct aead_request *req, */ static void init_ablkcipher_job(u32 *sh_desc, dma_addr_t ptr, struct ablkcipher_edesc *edesc, - struct ablkcipher_request *req, - bool iv_contig) + struct ablkcipher_request *req) { struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); int ivsize = crypto_ablkcipher_ivsize(ablkcipher); u32 *desc = edesc->hw_desc; - u32 out_options = 0, in_options; - dma_addr_t dst_dma, src_dma; - int len, sec4_sg_index = 0; + u32 out_options = 0; + dma_addr_t dst_dma; + int len; #ifdef DEBUG print_hex_dump(KERN_ERR, "presciv@"__stringify(__LINE__)": ", @@ -1123,30 +1130,18 @@ static void init_ablkcipher_job(u32 *sh_desc, dma_addr_t ptr, len = desc_len(sh_desc); init_job_desc_shared(desc, ptr, len, HDR_SHARE_DEFER | HDR_REVERSE); - if (iv_contig) { - src_dma = edesc->iv_dma; - in_options = 0; - } else { - src_dma = edesc->sec4_sg_dma; - sec4_sg_index += edesc->src_nents + 1; - in_options = LDST_SGF; - } - append_seq_in_ptr(desc, src_dma, req->nbytes + ivsize, in_options); + append_seq_in_ptr(desc, edesc->sec4_sg_dma, req->nbytes + ivsize, + LDST_SGF); if (likely(req->src == req->dst)) { - if (edesc->src_nents == 1 && iv_contig) { - dst_dma = sg_dma_address(req->src); - } else { - dst_dma = edesc->sec4_sg_dma + - sizeof(struct sec4_sg_entry); - out_options = LDST_SGF; - } + dst_dma = edesc->sec4_sg_dma + sizeof(struct sec4_sg_entry); + out_options = LDST_SGF; } else { if (edesc->dst_nents == 1) { dst_dma = sg_dma_address(req->dst); } else { - dst_dma = edesc->sec4_sg_dma + - sec4_sg_index * sizeof(struct sec4_sg_entry); + dst_dma = edesc->sec4_sg_dma + (edesc->src_nents + 1) * + sizeof(struct sec4_sg_entry); out_options = LDST_SGF; } } @@ -1158,13 +1153,12 @@ static void init_ablkcipher_job(u32 *sh_desc, dma_addr_t ptr, */ static void init_ablkcipher_giv_job(u32 *sh_desc, dma_addr_t ptr, struct ablkcipher_edesc *edesc, - struct ablkcipher_request *req, - bool iv_contig) + struct ablkcipher_request *req) { struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); int ivsize = crypto_ablkcipher_ivsize(ablkcipher); u32 *desc = edesc->hw_desc; - u32 out_options, in_options; + u32 in_options; dma_addr_t dst_dma, src_dma; int len, sec4_sg_index = 0; @@ -1190,15 +1184,9 @@ static void init_ablkcipher_giv_job(u32 *sh_desc, dma_addr_t ptr, } append_seq_in_ptr(desc, src_dma, req->nbytes, in_options); - if (iv_contig) { - dst_dma = edesc->iv_dma; - out_options = 0; - } else { - dst_dma = edesc->sec4_sg_dma + - sec4_sg_index * sizeof(struct sec4_sg_entry); - out_options = LDST_SGF; - } - append_seq_out_ptr(desc, dst_dma, req->nbytes + ivsize, out_options); + dst_dma = edesc->sec4_sg_dma + sec4_sg_index * + sizeof(struct sec4_sg_entry); + append_seq_out_ptr(desc, dst_dma, req->nbytes + ivsize, LDST_SGF); } /* @@ -1287,7 +1275,7 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, GFP_DMA | flags); if (!edesc) { caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, 0, - 0, 0, 0); + 0, DMA_NONE, 0, 0); return ERR_PTR(-ENOMEM); } @@ -1491,8 +1479,7 @@ static int aead_decrypt(struct aead_request *req) * allocate and map the ablkcipher extended descriptor for ablkcipher */ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request - *req, int desc_bytes, - bool *iv_contig_out) + *req, int desc_bytes) { struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); @@ -1501,8 +1488,8 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request GFP_KERNEL : GFP_ATOMIC; int src_nents, mapped_src_nents, dst_nents = 0, mapped_dst_nents = 0; struct ablkcipher_edesc *edesc; - dma_addr_t iv_dma = 0; - bool in_contig; + dma_addr_t iv_dma; + u8 *iv; int ivsize = crypto_ablkcipher_ivsize(ablkcipher); int dst_sg_idx, sec4_sg_ents, sec4_sg_bytes; @@ -1546,33 +1533,20 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request } } - iv_dma = dma_map_single(jrdev, req->info, ivsize, DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, iv_dma)) { - dev_err(jrdev, "unable to map IV\n"); - caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, 0, - 0, 0, 0); - return ERR_PTR(-ENOMEM); - } - - if (mapped_src_nents == 1 && - iv_dma + ivsize == sg_dma_address(req->src)) { - in_contig = true; - sec4_sg_ents = 0; - } else { - in_contig = false; - sec4_sg_ents = 1 + mapped_src_nents; - } + sec4_sg_ents = 1 + mapped_src_nents; dst_sg_idx = sec4_sg_ents; sec4_sg_ents += mapped_dst_nents > 1 ? mapped_dst_nents : 0; sec4_sg_bytes = sec4_sg_ents * sizeof(struct sec4_sg_entry); - /* allocate space for base edesc and hw desc commands, link tables */ - edesc = kzalloc(sizeof(*edesc) + desc_bytes + sec4_sg_bytes, + /* + * allocate space for base edesc and hw desc commands, link tables, IV + */ + edesc = kzalloc(sizeof(*edesc) + desc_bytes + sec4_sg_bytes + ivsize, GFP_DMA | flags); if (!edesc) { dev_err(jrdev, "could not allocate extended descriptor\n"); - caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, - iv_dma, ivsize, 0, 0); + caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, 0, + 0, DMA_NONE, 0, 0); return ERR_PTR(-ENOMEM); } @@ -1581,13 +1555,24 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request edesc->sec4_sg_bytes = sec4_sg_bytes; edesc->sec4_sg = (void *)edesc + sizeof(struct ablkcipher_edesc) + desc_bytes; + edesc->iv_dir = DMA_TO_DEVICE; - if (!in_contig) { - dma_to_sec4_sg_one(edesc->sec4_sg, iv_dma, ivsize, 0); - sg_to_sec4_sg_last(req->src, mapped_src_nents, - edesc->sec4_sg + 1, 0); + /* Make sure IV is located in a DMAable area */ + iv = (u8 *)edesc->hw_desc + desc_bytes + sec4_sg_bytes; + memcpy(iv, req->info, ivsize); + + iv_dma = dma_map_single(jrdev, iv, ivsize, DMA_TO_DEVICE); + if (dma_mapping_error(jrdev, iv_dma)) { + dev_err(jrdev, "unable to map IV\n"); + caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, 0, + 0, DMA_NONE, 0, 0); + kfree(edesc); + return ERR_PTR(-ENOMEM); } + dma_to_sec4_sg_one(edesc->sec4_sg, iv_dma, ivsize, 0); + sg_to_sec4_sg_last(req->src, mapped_src_nents, edesc->sec4_sg + 1, 0); + if (mapped_dst_nents > 1) { sg_to_sec4_sg_last(req->dst, mapped_dst_nents, edesc->sec4_sg + dst_sg_idx, 0); @@ -1598,7 +1583,7 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request if (dma_mapping_error(jrdev, edesc->sec4_sg_dma)) { dev_err(jrdev, "unable to map S/G table\n"); caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, - iv_dma, ivsize, 0, 0); + iv_dma, ivsize, DMA_TO_DEVICE, 0, 0); kfree(edesc); return ERR_PTR(-ENOMEM); } @@ -1611,7 +1596,6 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request sec4_sg_bytes, 1); #endif - *iv_contig_out = in_contig; return edesc; } @@ -1621,19 +1605,16 @@ static int ablkcipher_encrypt(struct ablkcipher_request *req) struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); struct device *jrdev = ctx->jrdev; - bool iv_contig; u32 *desc; int ret = 0; /* allocate extended descriptor */ - edesc = ablkcipher_edesc_alloc(req, DESC_JOB_IO_LEN * - CAAM_CMD_SZ, &iv_contig); + edesc = ablkcipher_edesc_alloc(req, DESC_JOB_IO_LEN * CAAM_CMD_SZ); if (IS_ERR(edesc)) return PTR_ERR(edesc); /* Create and submit job descriptor*/ - init_ablkcipher_job(ctx->sh_desc_enc, - ctx->sh_desc_enc_dma, edesc, req, iv_contig); + init_ablkcipher_job(ctx->sh_desc_enc, ctx->sh_desc_enc_dma, edesc, req); #ifdef DEBUG print_hex_dump(KERN_ERR, "ablkcipher jobdesc@"__stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc, @@ -1657,20 +1638,25 @@ static int ablkcipher_decrypt(struct ablkcipher_request *req) struct ablkcipher_edesc *edesc; struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); + int ivsize = crypto_ablkcipher_ivsize(ablkcipher); struct device *jrdev = ctx->jrdev; - bool iv_contig; u32 *desc; int ret = 0; /* allocate extended descriptor */ - edesc = ablkcipher_edesc_alloc(req, DESC_JOB_IO_LEN * - CAAM_CMD_SZ, &iv_contig); + edesc = ablkcipher_edesc_alloc(req, DESC_JOB_IO_LEN * CAAM_CMD_SZ); if (IS_ERR(edesc)) return PTR_ERR(edesc); + /* + * The crypto API expects us to set the IV (req->info) to the last + * ciphertext block. + */ + scatterwalk_map_and_copy(req->info, req->src, req->nbytes - ivsize, + ivsize, 0); + /* Create and submit job descriptor*/ - init_ablkcipher_job(ctx->sh_desc_dec, - ctx->sh_desc_dec_dma, edesc, req, iv_contig); + init_ablkcipher_job(ctx->sh_desc_dec, ctx->sh_desc_dec_dma, edesc, req); desc = edesc->hw_desc; #ifdef DEBUG print_hex_dump(KERN_ERR, "ablkcipher jobdesc@"__stringify(__LINE__)": ", @@ -1695,8 +1681,7 @@ static int ablkcipher_decrypt(struct ablkcipher_request *req) */ static struct ablkcipher_edesc *ablkcipher_giv_edesc_alloc( struct skcipher_givcrypt_request *greq, - int desc_bytes, - bool *iv_contig_out) + int desc_bytes) { struct ablkcipher_request *req = &greq->creq; struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); @@ -1706,8 +1691,8 @@ static struct ablkcipher_edesc *ablkcipher_giv_edesc_alloc( GFP_KERNEL : GFP_ATOMIC; int src_nents, mapped_src_nents, dst_nents, mapped_dst_nents; struct ablkcipher_edesc *edesc; - dma_addr_t iv_dma = 0; - bool out_contig; + dma_addr_t iv_dma; + u8 *iv; int ivsize = crypto_ablkcipher_ivsize(ablkcipher); int dst_sg_idx, sec4_sg_ents, sec4_sg_bytes; @@ -1752,36 +1737,20 @@ static struct ablkcipher_edesc *ablkcipher_giv_edesc_alloc( } } - /* - * Check if iv can be contiguous with source and destination. - * If so, include it. If not, create scatterlist. - */ - iv_dma = dma_map_single(jrdev, greq->giv, ivsize, DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, iv_dma)) { - dev_err(jrdev, "unable to map IV\n"); - caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, 0, - 0, 0, 0); - return ERR_PTR(-ENOMEM); - } - sec4_sg_ents = mapped_src_nents > 1 ? mapped_src_nents : 0; dst_sg_idx = sec4_sg_ents; - if (mapped_dst_nents == 1 && - iv_dma + ivsize == sg_dma_address(req->dst)) { - out_contig = true; - } else { - out_contig = false; - sec4_sg_ents += 1 + mapped_dst_nents; - } + sec4_sg_ents += 1 + mapped_dst_nents; - /* allocate space for base edesc and hw desc commands, link tables */ + /* + * allocate space for base edesc and hw desc commands, link tables, IV + */ sec4_sg_bytes = sec4_sg_ents * sizeof(struct sec4_sg_entry); - edesc = kzalloc(sizeof(*edesc) + desc_bytes + sec4_sg_bytes, + edesc = kzalloc(sizeof(*edesc) + desc_bytes + sec4_sg_bytes + ivsize, GFP_DMA | flags); if (!edesc) { dev_err(jrdev, "could not allocate extended descriptor\n"); - caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, - iv_dma, ivsize, 0, 0); + caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, 0, + 0, DMA_NONE, 0, 0); return ERR_PTR(-ENOMEM); } @@ -1790,24 +1759,33 @@ static struct ablkcipher_edesc *ablkcipher_giv_edesc_alloc( edesc->sec4_sg_bytes = sec4_sg_bytes; edesc->sec4_sg = (void *)edesc + sizeof(struct ablkcipher_edesc) + desc_bytes; + edesc->iv_dir = DMA_FROM_DEVICE; + + /* Make sure IV is located in a DMAable area */ + iv = (u8 *)edesc->hw_desc + desc_bytes + sec4_sg_bytes; + iv_dma = dma_map_single(jrdev, iv, ivsize, DMA_FROM_DEVICE); + if (dma_mapping_error(jrdev, iv_dma)) { + dev_err(jrdev, "unable to map IV\n"); + caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, 0, + 0, DMA_NONE, 0, 0); + kfree(edesc); + return ERR_PTR(-ENOMEM); + } if (mapped_src_nents > 1) sg_to_sec4_sg_last(req->src, mapped_src_nents, edesc->sec4_sg, 0); - if (!out_contig) { - dma_to_sec4_sg_one(edesc->sec4_sg + dst_sg_idx, - iv_dma, ivsize, 0); - sg_to_sec4_sg_last(req->dst, mapped_dst_nents, - edesc->sec4_sg + dst_sg_idx + 1, 0); - } + dma_to_sec4_sg_one(edesc->sec4_sg + dst_sg_idx, iv_dma, ivsize, 0); + sg_to_sec4_sg_last(req->dst, mapped_dst_nents, edesc->sec4_sg + + dst_sg_idx + 1, 0); edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, sec4_sg_bytes, DMA_TO_DEVICE); if (dma_mapping_error(jrdev, edesc->sec4_sg_dma)) { dev_err(jrdev, "unable to map S/G table\n"); caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, - iv_dma, ivsize, 0, 0); + iv_dma, ivsize, DMA_FROM_DEVICE, 0, 0); kfree(edesc); return ERR_PTR(-ENOMEM); } @@ -1820,7 +1798,6 @@ static struct ablkcipher_edesc *ablkcipher_giv_edesc_alloc( sec4_sg_bytes, 1); #endif - *iv_contig_out = out_contig; return edesc; } @@ -1831,19 +1808,17 @@ static int ablkcipher_givencrypt(struct skcipher_givcrypt_request *creq) struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); struct device *jrdev = ctx->jrdev; - bool iv_contig = false; u32 *desc; int ret = 0; /* allocate extended descriptor */ - edesc = ablkcipher_giv_edesc_alloc(creq, DESC_JOB_IO_LEN * - CAAM_CMD_SZ, &iv_contig); + edesc = ablkcipher_giv_edesc_alloc(creq, DESC_JOB_IO_LEN * CAAM_CMD_SZ); if (IS_ERR(edesc)) return PTR_ERR(edesc); /* Create and submit job descriptor*/ init_ablkcipher_giv_job(ctx->sh_desc_givenc, ctx->sh_desc_givenc_dma, - edesc, req, iv_contig); + edesc, req); #ifdef DEBUG print_hex_dump(KERN_ERR, "ablkcipher jobdesc@" __stringify(__LINE__) ": ", diff --git a/drivers/crypto/caam/caamalg_desc.c b/drivers/crypto/caam/caamalg_desc.c index 8ae7a1be7dfd..a408edd84f34 100644 --- a/drivers/crypto/caam/caamalg_desc.c +++ b/drivers/crypto/caam/caamalg_desc.c @@ -1093,7 +1093,7 @@ void cnstr_shdsc_rfc4543_encap(u32 * const desc, struct alginfo *cdata, read_move_cmd = append_move(desc, MOVE_SRC_DESCBUF | MOVE_DEST_MATH3 | (0x6 << MOVE_LEN_SHIFT)); write_move_cmd = append_move(desc, MOVE_SRC_MATH3 | MOVE_DEST_DESCBUF | - (0x8 << MOVE_LEN_SHIFT)); + (0x8 << MOVE_LEN_SHIFT) | MOVE_WAITCOMP); /* Will read assoclen + cryptlen bytes */ append_math_sub(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); @@ -1178,7 +1178,7 @@ void cnstr_shdsc_rfc4543_decap(u32 * const desc, struct alginfo *cdata, read_move_cmd = append_move(desc, MOVE_SRC_DESCBUF | MOVE_DEST_MATH3 | (0x6 << MOVE_LEN_SHIFT)); write_move_cmd = append_move(desc, MOVE_SRC_MATH3 | MOVE_DEST_DESCBUF | - (0x8 << MOVE_LEN_SHIFT)); + (0x8 << MOVE_LEN_SHIFT) | MOVE_WAITCOMP); /* Will read assoclen + cryptlen bytes */ append_math_sub(desc, VARSEQINLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ); diff --git a/drivers/crypto/caam/caamalg_qi.c b/drivers/crypto/caam/caamalg_qi.c index cacda0831390..6e61cc93c2b0 100644 --- a/drivers/crypto/caam/caamalg_qi.c +++ b/drivers/crypto/caam/caamalg_qi.c @@ -728,7 +728,7 @@ badkey: * @assoclen: associated data length, in CAAM endianness * @assoclen_dma: bus physical mapped address of req->assoclen * @drv_req: driver-specific request structure - * @sgt: the h/w link table + * @sgt: the h/w link table, followed by IV */ struct aead_edesc { int src_nents; @@ -739,9 +739,6 @@ struct aead_edesc { unsigned int assoclen; dma_addr_t assoclen_dma; struct caam_drv_req drv_req; -#define CAAM_QI_MAX_AEAD_SG \ - ((CAAM_QI_MEMCACHE_SIZE - offsetof(struct aead_edesc, sgt)) / \ - sizeof(struct qm_sg_entry)) struct qm_sg_entry sgt[0]; }; @@ -753,7 +750,7 @@ struct aead_edesc { * @qm_sg_bytes: length of dma mapped h/w link table * @qm_sg_dma: bus physical mapped address of h/w link table * @drv_req: driver-specific request structure - * @sgt: the h/w link table + * @sgt: the h/w link table, followed by IV */ struct ablkcipher_edesc { int src_nents; @@ -762,9 +759,6 @@ struct ablkcipher_edesc { int qm_sg_bytes; dma_addr_t qm_sg_dma; struct caam_drv_req drv_req; -#define CAAM_QI_MAX_ABLKCIPHER_SG \ - ((CAAM_QI_MEMCACHE_SIZE - offsetof(struct ablkcipher_edesc, sgt)) / \ - sizeof(struct qm_sg_entry)) struct qm_sg_entry sgt[0]; }; @@ -986,17 +980,8 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, } } - if ((alg->caam.rfc3686 && encrypt) || !alg->caam.geniv) { + if ((alg->caam.rfc3686 && encrypt) || !alg->caam.geniv) ivsize = crypto_aead_ivsize(aead); - iv_dma = dma_map_single(qidev, req->iv, ivsize, DMA_TO_DEVICE); - if (dma_mapping_error(qidev, iv_dma)) { - dev_err(qidev, "unable to map IV\n"); - caam_unmap(qidev, req->src, req->dst, src_nents, - dst_nents, 0, 0, op_type, 0, 0); - qi_cache_free(edesc); - return ERR_PTR(-ENOMEM); - } - } /* * Create S/G table: req->assoclen, [IV,] req->src [, req->dst]. @@ -1004,16 +989,33 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, */ qm_sg_ents = 1 + !!ivsize + mapped_src_nents + (mapped_dst_nents > 1 ? mapped_dst_nents : 0); - if (unlikely(qm_sg_ents > CAAM_QI_MAX_AEAD_SG)) { - dev_err(qidev, "Insufficient S/G entries: %d > %zu\n", - qm_sg_ents, CAAM_QI_MAX_AEAD_SG); - caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, - iv_dma, ivsize, op_type, 0, 0); + sg_table = &edesc->sgt[0]; + qm_sg_bytes = qm_sg_ents * sizeof(*sg_table); + if (unlikely(offsetof(struct aead_edesc, sgt) + qm_sg_bytes + ivsize > + CAAM_QI_MEMCACHE_SIZE)) { + dev_err(qidev, "No space for %d S/G entries and/or %dB IV\n", + qm_sg_ents, ivsize); + caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0, + 0, 0, 0, 0); qi_cache_free(edesc); return ERR_PTR(-ENOMEM); } - sg_table = &edesc->sgt[0]; - qm_sg_bytes = qm_sg_ents * sizeof(*sg_table); + + if (ivsize) { + u8 *iv = (u8 *)(sg_table + qm_sg_ents); + + /* Make sure IV is located in a DMAable area */ + memcpy(iv, req->iv, ivsize); + + iv_dma = dma_map_single(qidev, iv, ivsize, DMA_TO_DEVICE); + if (dma_mapping_error(qidev, iv_dma)) { + dev_err(qidev, "unable to map IV\n"); + caam_unmap(qidev, req->src, req->dst, src_nents, + dst_nents, 0, 0, 0, 0, 0); + qi_cache_free(edesc); + return ERR_PTR(-ENOMEM); + } + } edesc->src_nents = src_nents; edesc->dst_nents = dst_nents; @@ -1166,15 +1168,27 @@ static void ablkcipher_done(struct caam_drv_req *drv_req, u32 status) #endif ablkcipher_unmap(qidev, edesc, req); - qi_cache_free(edesc); + + /* In case initial IV was generated, copy it in GIVCIPHER request */ + if (edesc->drv_req.drv_ctx->op_type == GIVENCRYPT) { + u8 *iv; + struct skcipher_givcrypt_request *greq; + + greq = container_of(req, struct skcipher_givcrypt_request, + creq); + iv = (u8 *)edesc->sgt + edesc->qm_sg_bytes; + memcpy(greq->giv, iv, ivsize); + } /* * The crypto API expects us to set the IV (req->info) to the last * ciphertext block. This is used e.g. by the CTS mode. */ - scatterwalk_map_and_copy(req->info, req->dst, req->nbytes - ivsize, - ivsize, 0); + if (edesc->drv_req.drv_ctx->op_type != DECRYPT) + scatterwalk_map_and_copy(req->info, req->dst, req->nbytes - + ivsize, ivsize, 0); + qi_cache_free(edesc); ablkcipher_request_complete(req, status); } @@ -1189,9 +1203,9 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request int src_nents, mapped_src_nents, dst_nents = 0, mapped_dst_nents = 0; struct ablkcipher_edesc *edesc; dma_addr_t iv_dma; - bool in_contig; + u8 *iv; int ivsize = crypto_ablkcipher_ivsize(ablkcipher); - int dst_sg_idx, qm_sg_ents; + int dst_sg_idx, qm_sg_ents, qm_sg_bytes; struct qm_sg_entry *sg_table, *fd_sgt; struct caam_drv_ctx *drv_ctx; enum optype op_type = encrypt ? ENCRYPT : DECRYPT; @@ -1238,55 +1252,53 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request } } - iv_dma = dma_map_single(qidev, req->info, ivsize, DMA_TO_DEVICE); - if (dma_mapping_error(qidev, iv_dma)) { - dev_err(qidev, "unable to map IV\n"); - caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0, - 0, 0, 0, 0); - return ERR_PTR(-ENOMEM); - } - - if (mapped_src_nents == 1 && - iv_dma + ivsize == sg_dma_address(req->src)) { - in_contig = true; - qm_sg_ents = 0; - } else { - in_contig = false; - qm_sg_ents = 1 + mapped_src_nents; - } + qm_sg_ents = 1 + mapped_src_nents; dst_sg_idx = qm_sg_ents; qm_sg_ents += mapped_dst_nents > 1 ? mapped_dst_nents : 0; - if (unlikely(qm_sg_ents > CAAM_QI_MAX_ABLKCIPHER_SG)) { - dev_err(qidev, "Insufficient S/G entries: %d > %zu\n", - qm_sg_ents, CAAM_QI_MAX_ABLKCIPHER_SG); - caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, - iv_dma, ivsize, op_type, 0, 0); + qm_sg_bytes = qm_sg_ents * sizeof(struct qm_sg_entry); + if (unlikely(offsetof(struct ablkcipher_edesc, sgt) + qm_sg_bytes + + ivsize > CAAM_QI_MEMCACHE_SIZE)) { + dev_err(qidev, "No space for %d S/G entries and/or %dB IV\n", + qm_sg_ents, ivsize); + caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0, + 0, 0, 0, 0); return ERR_PTR(-ENOMEM); } - /* allocate space for base edesc and link tables */ + /* allocate space for base edesc, link tables and IV */ edesc = qi_cache_alloc(GFP_DMA | flags); if (unlikely(!edesc)) { dev_err(qidev, "could not allocate extended descriptor\n"); - caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, - iv_dma, ivsize, op_type, 0, 0); + caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0, + 0, 0, 0, 0); + return ERR_PTR(-ENOMEM); + } + + /* Make sure IV is located in a DMAable area */ + sg_table = &edesc->sgt[0]; + iv = (u8 *)(sg_table + qm_sg_ents); + memcpy(iv, req->info, ivsize); + + iv_dma = dma_map_single(qidev, iv, ivsize, DMA_TO_DEVICE); + if (dma_mapping_error(qidev, iv_dma)) { + dev_err(qidev, "unable to map IV\n"); + caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0, + 0, 0, 0, 0); + qi_cache_free(edesc); return ERR_PTR(-ENOMEM); } edesc->src_nents = src_nents; edesc->dst_nents = dst_nents; edesc->iv_dma = iv_dma; - sg_table = &edesc->sgt[0]; - edesc->qm_sg_bytes = qm_sg_ents * sizeof(*sg_table); + edesc->qm_sg_bytes = qm_sg_bytes; edesc->drv_req.app_ctx = req; edesc->drv_req.cbk = ablkcipher_done; edesc->drv_req.drv_ctx = drv_ctx; - if (!in_contig) { - dma_to_qm_sg_one(sg_table, iv_dma, ivsize, 0); - sg_to_qm_sg_last(req->src, mapped_src_nents, sg_table + 1, 0); - } + dma_to_qm_sg_one(sg_table, iv_dma, ivsize, 0); + sg_to_qm_sg_last(req->src, mapped_src_nents, sg_table + 1, 0); if (mapped_dst_nents > 1) sg_to_qm_sg_last(req->dst, mapped_dst_nents, sg_table + @@ -1304,20 +1316,12 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request fd_sgt = &edesc->drv_req.fd_sgt[0]; - if (!in_contig) - dma_to_qm_sg_one_last_ext(&fd_sgt[1], edesc->qm_sg_dma, - ivsize + req->nbytes, 0); - else - dma_to_qm_sg_one_last(&fd_sgt[1], iv_dma, ivsize + req->nbytes, - 0); + dma_to_qm_sg_one_last_ext(&fd_sgt[1], edesc->qm_sg_dma, + ivsize + req->nbytes, 0); if (req->src == req->dst) { - if (!in_contig) - dma_to_qm_sg_one_ext(&fd_sgt[0], edesc->qm_sg_dma + - sizeof(*sg_table), req->nbytes, 0); - else - dma_to_qm_sg_one(&fd_sgt[0], sg_dma_address(req->src), - req->nbytes, 0); + dma_to_qm_sg_one_ext(&fd_sgt[0], edesc->qm_sg_dma + + sizeof(*sg_table), req->nbytes, 0); } else if (mapped_dst_nents > 1) { dma_to_qm_sg_one_ext(&fd_sgt[0], edesc->qm_sg_dma + dst_sg_idx * sizeof(*sg_table), req->nbytes, 0); @@ -1341,10 +1345,10 @@ static struct ablkcipher_edesc *ablkcipher_giv_edesc_alloc( int src_nents, mapped_src_nents, dst_nents, mapped_dst_nents; struct ablkcipher_edesc *edesc; dma_addr_t iv_dma; - bool out_contig; + u8 *iv; int ivsize = crypto_ablkcipher_ivsize(ablkcipher); struct qm_sg_entry *sg_table, *fd_sgt; - int dst_sg_idx, qm_sg_ents; + int dst_sg_idx, qm_sg_ents, qm_sg_bytes; struct caam_drv_ctx *drv_ctx; drv_ctx = get_drv_ctx(ctx, GIVENCRYPT); @@ -1392,46 +1396,45 @@ static struct ablkcipher_edesc *ablkcipher_giv_edesc_alloc( mapped_dst_nents = src_nents; } - iv_dma = dma_map_single(qidev, creq->giv, ivsize, DMA_FROM_DEVICE); - if (dma_mapping_error(qidev, iv_dma)) { - dev_err(qidev, "unable to map IV\n"); - caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0, - 0, 0, 0, 0); - return ERR_PTR(-ENOMEM); - } - qm_sg_ents = mapped_src_nents > 1 ? mapped_src_nents : 0; dst_sg_idx = qm_sg_ents; - if (mapped_dst_nents == 1 && - iv_dma + ivsize == sg_dma_address(req->dst)) { - out_contig = true; - } else { - out_contig = false; - qm_sg_ents += 1 + mapped_dst_nents; - } - if (unlikely(qm_sg_ents > CAAM_QI_MAX_ABLKCIPHER_SG)) { - dev_err(qidev, "Insufficient S/G entries: %d > %zu\n", - qm_sg_ents, CAAM_QI_MAX_ABLKCIPHER_SG); - caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, - iv_dma, ivsize, GIVENCRYPT, 0, 0); + qm_sg_ents += 1 + mapped_dst_nents; + qm_sg_bytes = qm_sg_ents * sizeof(struct qm_sg_entry); + if (unlikely(offsetof(struct ablkcipher_edesc, sgt) + qm_sg_bytes + + ivsize > CAAM_QI_MEMCACHE_SIZE)) { + dev_err(qidev, "No space for %d S/G entries and/or %dB IV\n", + qm_sg_ents, ivsize); + caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0, + 0, 0, 0, 0); return ERR_PTR(-ENOMEM); } - /* allocate space for base edesc and link tables */ + /* allocate space for base edesc, link tables and IV */ edesc = qi_cache_alloc(GFP_DMA | flags); if (!edesc) { dev_err(qidev, "could not allocate extended descriptor\n"); - caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, - iv_dma, ivsize, GIVENCRYPT, 0, 0); + caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0, + 0, 0, 0, 0); + return ERR_PTR(-ENOMEM); + } + + /* Make sure IV is located in a DMAable area */ + sg_table = &edesc->sgt[0]; + iv = (u8 *)(sg_table + qm_sg_ents); + iv_dma = dma_map_single(qidev, iv, ivsize, DMA_FROM_DEVICE); + if (dma_mapping_error(qidev, iv_dma)) { + dev_err(qidev, "unable to map IV\n"); + caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0, + 0, 0, 0, 0); + qi_cache_free(edesc); return ERR_PTR(-ENOMEM); } edesc->src_nents = src_nents; edesc->dst_nents = dst_nents; edesc->iv_dma = iv_dma; - sg_table = &edesc->sgt[0]; - edesc->qm_sg_bytes = qm_sg_ents * sizeof(*sg_table); + edesc->qm_sg_bytes = qm_sg_bytes; edesc->drv_req.app_ctx = req; edesc->drv_req.cbk = ablkcipher_done; edesc->drv_req.drv_ctx = drv_ctx; @@ -1439,11 +1442,9 @@ static struct ablkcipher_edesc *ablkcipher_giv_edesc_alloc( if (mapped_src_nents > 1) sg_to_qm_sg_last(req->src, mapped_src_nents, sg_table, 0); - if (!out_contig) { - dma_to_qm_sg_one(sg_table + dst_sg_idx, iv_dma, ivsize, 0); - sg_to_qm_sg_last(req->dst, mapped_dst_nents, sg_table + - dst_sg_idx + 1, 0); - } + dma_to_qm_sg_one(sg_table + dst_sg_idx, iv_dma, ivsize, 0); + sg_to_qm_sg_last(req->dst, mapped_dst_nents, sg_table + dst_sg_idx + 1, + 0); edesc->qm_sg_dma = dma_map_single(qidev, sg_table, edesc->qm_sg_bytes, DMA_TO_DEVICE); @@ -1464,13 +1465,8 @@ static struct ablkcipher_edesc *ablkcipher_giv_edesc_alloc( dma_to_qm_sg_one(&fd_sgt[1], sg_dma_address(req->src), req->nbytes, 0); - if (!out_contig) - dma_to_qm_sg_one_ext(&fd_sgt[0], edesc->qm_sg_dma + dst_sg_idx * - sizeof(*sg_table), ivsize + req->nbytes, - 0); - else - dma_to_qm_sg_one(&fd_sgt[0], sg_dma_address(req->dst), - ivsize + req->nbytes, 0); + dma_to_qm_sg_one_ext(&fd_sgt[0], edesc->qm_sg_dma + dst_sg_idx * + sizeof(*sg_table), ivsize + req->nbytes, 0); return edesc; } @@ -1480,6 +1476,7 @@ static inline int ablkcipher_crypt(struct ablkcipher_request *req, bool encrypt) struct ablkcipher_edesc *edesc; struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); + int ivsize = crypto_ablkcipher_ivsize(ablkcipher); int ret; if (unlikely(caam_congested)) @@ -1490,6 +1487,14 @@ static inline int ablkcipher_crypt(struct ablkcipher_request *req, bool encrypt) if (IS_ERR(edesc)) return PTR_ERR(edesc); + /* + * The crypto API expects us to set the IV (req->info) to the last + * ciphertext block. + */ + if (!encrypt) + scatterwalk_map_and_copy(req->info, req->src, req->nbytes - + ivsize, ivsize, 0); + ret = caam_qi_enqueue(ctx->qidev, &edesc->drv_req); if (!ret) { ret = -EINPROGRESS; diff --git a/drivers/crypto/caam/caampkc.c b/drivers/crypto/caam/caampkc.c index 7a897209f181..578ea63a3109 100644 --- a/drivers/crypto/caam/caampkc.c +++ b/drivers/crypto/caam/caampkc.c @@ -66,7 +66,7 @@ static void rsa_priv_f2_unmap(struct device *dev, struct rsa_edesc *edesc, struct caam_rsa_key *key = &ctx->key; struct rsa_priv_f2_pdb *pdb = &edesc->pdb.priv_f2; size_t p_sz = key->p_sz; - size_t q_sz = key->p_sz; + size_t q_sz = key->q_sz; dma_unmap_single(dev, pdb->d_dma, key->d_sz, DMA_TO_DEVICE); dma_unmap_single(dev, pdb->p_dma, p_sz, DMA_TO_DEVICE); @@ -83,7 +83,7 @@ static void rsa_priv_f3_unmap(struct device *dev, struct rsa_edesc *edesc, struct caam_rsa_key *key = &ctx->key; struct rsa_priv_f3_pdb *pdb = &edesc->pdb.priv_f3; size_t p_sz = key->p_sz; - size_t q_sz = key->p_sz; + size_t q_sz = key->q_sz; dma_unmap_single(dev, pdb->p_dma, p_sz, DMA_TO_DEVICE); dma_unmap_single(dev, pdb->q_dma, q_sz, DMA_TO_DEVICE); @@ -166,18 +166,71 @@ static void rsa_priv_f3_done(struct device *dev, u32 *desc, u32 err, akcipher_request_complete(req, err); } +static int caam_rsa_count_leading_zeros(struct scatterlist *sgl, + unsigned int nbytes, + unsigned int flags) +{ + struct sg_mapping_iter miter; + int lzeros, ents; + unsigned int len; + unsigned int tbytes = nbytes; + const u8 *buff; + + ents = sg_nents_for_len(sgl, nbytes); + if (ents < 0) + return ents; + + sg_miter_start(&miter, sgl, ents, SG_MITER_FROM_SG | flags); + + lzeros = 0; + len = 0; + while (nbytes > 0) { + while (len && !*buff) { + lzeros++; + len--; + buff++; + } + + if (len && *buff) + break; + + sg_miter_next(&miter); + buff = miter.addr; + len = miter.length; + + nbytes -= lzeros; + lzeros = 0; + } + + miter.consumed = lzeros; + sg_miter_stop(&miter); + nbytes -= lzeros; + + return tbytes - nbytes; +} + static struct rsa_edesc *rsa_edesc_alloc(struct akcipher_request *req, size_t desclen) { struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm); struct device *dev = ctx->dev; + struct caam_rsa_req_ctx *req_ctx = akcipher_request_ctx(req); struct rsa_edesc *edesc; gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? GFP_KERNEL : GFP_ATOMIC; + int sg_flags = (flags == GFP_ATOMIC) ? SG_MITER_ATOMIC : 0; int sgc; int sec4_sg_index, sec4_sg_len = 0, sec4_sg_bytes; int src_nents, dst_nents; + int lzeros; + + lzeros = caam_rsa_count_leading_zeros(req->src, req->src_len, sg_flags); + if (lzeros < 0) + return ERR_PTR(lzeros); + + req->src_len -= lzeros; + req->src = scatterwalk_ffwd(req_ctx->src, req->src, lzeros); src_nents = sg_nents_for_len(req->src, req->src_len); dst_nents = sg_nents_for_len(req->dst, req->dst_len); @@ -344,7 +397,7 @@ static int set_rsa_priv_f2_pdb(struct akcipher_request *req, struct rsa_priv_f2_pdb *pdb = &edesc->pdb.priv_f2; int sec4_sg_index = 0; size_t p_sz = key->p_sz; - size_t q_sz = key->p_sz; + size_t q_sz = key->q_sz; pdb->d_dma = dma_map_single(dev, key->d, key->d_sz, DMA_TO_DEVICE); if (dma_mapping_error(dev, pdb->d_dma)) { @@ -419,7 +472,7 @@ static int set_rsa_priv_f3_pdb(struct akcipher_request *req, struct rsa_priv_f3_pdb *pdb = &edesc->pdb.priv_f3; int sec4_sg_index = 0; size_t p_sz = key->p_sz; - size_t q_sz = key->p_sz; + size_t q_sz = key->q_sz; pdb->p_dma = dma_map_single(dev, key->p, p_sz, DMA_TO_DEVICE); if (dma_mapping_error(dev, pdb->p_dma)) { @@ -730,19 +783,12 @@ static u8 *caam_read_rsa_crt(const u8 *ptr, size_t nbytes, size_t dstlen) */ static inline u8 *caam_read_raw_data(const u8 *buf, size_t *nbytes) { - u8 *val; caam_rsa_drop_leading_zeros(&buf, nbytes); if (!*nbytes) return NULL; - val = kzalloc(*nbytes, GFP_DMA | GFP_KERNEL); - if (!val) - return NULL; - - memcpy(val, buf, *nbytes); - - return val; + return kmemdup(buf, *nbytes, GFP_DMA | GFP_KERNEL); } static int caam_rsa_check_key_length(unsigned int len) @@ -953,6 +999,7 @@ static struct akcipher_alg caam_rsa = { .max_size = caam_rsa_max_size, .init = caam_rsa_init_tfm, .exit = caam_rsa_exit_tfm, + .reqsize = sizeof(struct caam_rsa_req_ctx), .base = { .cra_name = "rsa", .cra_driver_name = "rsa-caam", diff --git a/drivers/crypto/caam/caampkc.h b/drivers/crypto/caam/caampkc.h index fd145c46eae1..82645bcf8b27 100644 --- a/drivers/crypto/caam/caampkc.h +++ b/drivers/crypto/caam/caampkc.h @@ -96,6 +96,14 @@ struct caam_rsa_ctx { }; /** + * caam_rsa_req_ctx - per request context. + * @src: input scatterlist (stripped of leading zeros) + */ +struct caam_rsa_req_ctx { + struct scatterlist src[2]; +}; + +/** * rsa_edesc - s/w-extended rsa descriptor * @src_nents : number of segments in input scatterlist * @dst_nents : number of segments in output scatterlist diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c index e4cc636e1104..538c01f428c1 100644 --- a/drivers/crypto/caam/ctrl.c +++ b/drivers/crypto/caam/ctrl.c @@ -322,9 +322,9 @@ static int caam_remove(struct platform_device *pdev) /* * De-initialize RNG state handles initialized by this driver. - * In case of DPAA 2.x, RNG is managed by MC firmware. + * In case of SoCs with Management Complex, RNG is managed by MC f/w. */ - if (!caam_dpaa2 && ctrlpriv->rng4_sh_init) + if (!ctrlpriv->mc_en && ctrlpriv->rng4_sh_init) deinstantiate_rng(ctrldev, ctrlpriv->rng4_sh_init); /* Shut down debug views */ @@ -396,11 +396,56 @@ start_rng: clrsetbits_32(&r4tst->rtmctl, RTMCTL_PRGM, RTMCTL_SAMP_MODE_RAW_ES_SC); } +static int caam_get_era_from_hw(struct caam_ctrl __iomem *ctrl) +{ + static const struct { + u16 ip_id; + u8 maj_rev; + u8 era; + } id[] = { + {0x0A10, 1, 1}, + {0x0A10, 2, 2}, + {0x0A12, 1, 3}, + {0x0A14, 1, 3}, + {0x0A14, 2, 4}, + {0x0A16, 1, 4}, + {0x0A10, 3, 4}, + {0x0A11, 1, 4}, + {0x0A18, 1, 4}, + {0x0A11, 2, 5}, + {0x0A12, 2, 5}, + {0x0A13, 1, 5}, + {0x0A1C, 1, 5} + }; + u32 ccbvid, id_ms; + u8 maj_rev, era; + u16 ip_id; + int i; + + ccbvid = rd_reg32(&ctrl->perfmon.ccb_id); + era = (ccbvid & CCBVID_ERA_MASK) >> CCBVID_ERA_SHIFT; + if (era) /* This is '0' prior to CAAM ERA-6 */ + return era; + + id_ms = rd_reg32(&ctrl->perfmon.caam_id_ms); + ip_id = (id_ms & SECVID_MS_IPID_MASK) >> SECVID_MS_IPID_SHIFT; + maj_rev = (id_ms & SECVID_MS_MAJ_REV_MASK) >> SECVID_MS_MAJ_REV_SHIFT; + + for (i = 0; i < ARRAY_SIZE(id); i++) + if (id[i].ip_id == ip_id && id[i].maj_rev == maj_rev) + return id[i].era; + + return -ENOTSUPP; +} + /** * caam_get_era() - Return the ERA of the SEC on SoC, based - * on "sec-era" propery in the DTS. This property is updated by u-boot. + * on "sec-era" optional property in the DTS. This property is updated + * by u-boot. + * In case this property is not passed an attempt to retrieve the CAAM + * era via register reads will be made. **/ -int caam_get_era(void) +static int caam_get_era(struct caam_ctrl __iomem *ctrl) { struct device_node *caam_node; int ret; @@ -410,9 +455,11 @@ int caam_get_era(void) ret = of_property_read_u32(caam_node, "fsl,sec-era", &prop); of_node_put(caam_node); - return ret ? -ENOTSUPP : prop; + if (!ret) + return prop; + else + return caam_get_era_from_hw(ctrl); } -EXPORT_SYMBOL(caam_get_era); static const struct of_device_id caam_match[] = { { @@ -571,11 +618,15 @@ static int caam_probe(struct platform_device *pdev) /* * Enable DECO watchdogs and, if this is a PHYS_ADDR_T_64BIT kernel, * long pointers in master configuration register. - * In case of DPAA 2.x, Management Complex firmware performs + * In case of SoCs with Management Complex, MC f/w performs * the configuration. */ caam_dpaa2 = !!(comp_params & CTPR_MS_DPAA2); - if (!caam_dpaa2) + np = of_find_compatible_node(NULL, NULL, "fsl,qoriq-mc"); + ctrlpriv->mc_en = !!np; + of_node_put(np); + + if (!ctrlpriv->mc_en) clrsetbits_32(&ctrl->mcr, MCFGR_AWCACHE_MASK | MCFGR_LONG_PTR, MCFGR_AWCACHE_CACH | MCFGR_AWCACHE_BUFF | MCFGR_WDENABLE | MCFGR_LARGE_BURST | @@ -623,7 +674,7 @@ static int caam_probe(struct platform_device *pdev) goto iounmap_ctrl; } - ctrlpriv->era = caam_get_era(); + ctrlpriv->era = caam_get_era(ctrl); ret = of_platform_populate(nprop, caam_match, NULL, dev); if (ret) { @@ -686,9 +737,9 @@ static int caam_probe(struct platform_device *pdev) /* * If SEC has RNG version >= 4 and RNG state handle has not been * already instantiated, do RNG instantiation - * In case of DPAA 2.x, RNG is managed by MC firmware. + * In case of SoCs with Management Complex, RNG is managed by MC f/w. */ - if (!caam_dpaa2 && + if (!ctrlpriv->mc_en && (cha_vid_ls & CHA_ID_LS_RNG_MASK) >> CHA_ID_LS_RNG_SHIFT >= 4) { ctrlpriv->rng4_sh_init = rd_reg32(&ctrl->r4tst[0].rdsta); @@ -757,9 +808,8 @@ static int caam_probe(struct platform_device *pdev) /* Report "alive" for developer to see */ dev_info(dev, "device ID = 0x%016llx (Era %d)\n", caam_id, ctrlpriv->era); - dev_info(dev, "job rings = %d, qi = %d, dpaa2 = %s\n", - ctrlpriv->total_jobrs, ctrlpriv->qi_present, - caam_dpaa2 ? "yes" : "no"); + dev_info(dev, "job rings = %d, qi = %d\n", + ctrlpriv->total_jobrs, ctrlpriv->qi_present); #ifdef CONFIG_DEBUG_FS debugfs_create_file("rq_dequeued", S_IRUSR | S_IRGRP | S_IROTH, diff --git a/drivers/crypto/caam/ctrl.h b/drivers/crypto/caam/ctrl.h index be693a2cc25e..f3ecd67922a7 100644 --- a/drivers/crypto/caam/ctrl.h +++ b/drivers/crypto/caam/ctrl.h @@ -9,8 +9,6 @@ #define CTRL_H /* Prototypes for backend-level services exposed to APIs */ -int caam_get_era(void); - extern bool caam_dpaa2; #endif /* CTRL_H */ diff --git a/drivers/crypto/caam/intern.h b/drivers/crypto/caam/intern.h index 7696a774a362..babc78abd155 100644 --- a/drivers/crypto/caam/intern.h +++ b/drivers/crypto/caam/intern.h @@ -82,6 +82,7 @@ struct caam_drv_private { */ u8 total_jobrs; /* Total Job Rings in device */ u8 qi_present; /* Nonzero if QI present in device */ + u8 mc_en; /* Nonzero if MC f/w is active */ int secvio_irq; /* Security violation interrupt number */ int virt_en; /* Virtualization enabled in CAAM */ int era; /* CAAM Era (internal HW revision) */ diff --git a/drivers/crypto/caam/qi.c b/drivers/crypto/caam/qi.c index b9480828da38..67f7f8c42c93 100644 --- a/drivers/crypto/caam/qi.c +++ b/drivers/crypto/caam/qi.c @@ -657,9 +657,8 @@ static int init_cgr(struct device *qidev) { int ret; struct qm_mcc_initcgr opts; - const u64 cpus = *(u64 *)qman_affine_cpus(); - const int num_cpus = hweight64(cpus); - const u64 val = num_cpus * MAX_RSP_FQ_BACKLOG_PER_CPU; + const u64 val = (u64)cpumask_weight(qman_affine_cpus()) * + MAX_RSP_FQ_BACKLOG_PER_CPU; ret = qman_alloc_cgrid(&qipriv.cgr.cgrid); if (ret) { diff --git a/drivers/crypto/caam/regs.h b/drivers/crypto/caam/regs.h index fee363865d88..4fb91ba39c36 100644 --- a/drivers/crypto/caam/regs.h +++ b/drivers/crypto/caam/regs.h @@ -312,11 +312,17 @@ struct caam_perfmon { /* Component Instantiation Parameters fe0-fff */ u32 rtic_id; /* RVID - RTIC Version ID */ +#define CCBVID_ERA_MASK 0xff000000 +#define CCBVID_ERA_SHIFT 24 u32 ccb_id; /* CCBVID - CCB Version ID */ u32 cha_id_ms; /* CHAVID - CHA Version ID Most Significant*/ u32 cha_id_ls; /* CHAVID - CHA Version ID Least Significant*/ u32 cha_num_ms; /* CHANUM - CHA Number Most Significant */ u32 cha_num_ls; /* CHANUM - CHA Number Least Significant*/ +#define SECVID_MS_IPID_MASK 0xffff0000 +#define SECVID_MS_IPID_SHIFT 16 +#define SECVID_MS_MAJ_REV_MASK 0x0000ff00 +#define SECVID_MS_MAJ_REV_SHIFT 8 u32 caam_id_ms; /* CAAMVID - CAAM Version ID MS */ u32 caam_id_ls; /* CAAMVID - CAAM Version ID LS */ }; diff --git a/drivers/crypto/cavium/zip/common.h b/drivers/crypto/cavium/zip/common.h index dc451e0a43c5..58fb3ed6e644 100644 --- a/drivers/crypto/cavium/zip/common.h +++ b/drivers/crypto/cavium/zip/common.h @@ -46,8 +46,10 @@ #ifndef __COMMON_H__ #define __COMMON_H__ +#include <linux/delay.h> #include <linux/init.h> #include <linux/interrupt.h> +#include <linux/io.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> @@ -149,6 +151,25 @@ struct zip_operation { u32 sizeofzops; }; +static inline int zip_poll_result(union zip_zres_s *result) +{ + int retries = 1000; + + while (!result->s.compcode) { + if (!--retries) { + pr_err("ZIP ERR: request timed out"); + return -ETIMEDOUT; + } + udelay(10); + /* + * Force re-reading of compcode which is updated + * by the ZIP coprocessor. + */ + rmb(); + } + return 0; +} + /* error messages */ #define zip_err(fmt, args...) pr_err("ZIP ERR:%s():%d: " \ fmt "\n", __func__, __LINE__, ## args) diff --git a/drivers/crypto/cavium/zip/zip_crypto.c b/drivers/crypto/cavium/zip/zip_crypto.c index 8df4d26cf9d4..b92b6e7e100f 100644 --- a/drivers/crypto/cavium/zip/zip_crypto.c +++ b/drivers/crypto/cavium/zip/zip_crypto.c @@ -124,7 +124,7 @@ int zip_compress(const u8 *src, unsigned int slen, struct zip_kernel_ctx *zip_ctx) { struct zip_operation *zip_ops = NULL; - struct zip_state zip_state; + struct zip_state *zip_state; struct zip_device *zip = NULL; int ret; @@ -135,20 +135,23 @@ int zip_compress(const u8 *src, unsigned int slen, if (!zip) return -ENODEV; - memset(&zip_state, 0, sizeof(struct zip_state)); + zip_state = kzalloc(sizeof(*zip_state), GFP_ATOMIC); + if (!zip_state) + return -ENOMEM; + zip_ops = &zip_ctx->zip_comp; zip_ops->input_len = slen; zip_ops->output_len = *dlen; memcpy(zip_ops->input, src, slen); - ret = zip_deflate(zip_ops, &zip_state, zip); + ret = zip_deflate(zip_ops, zip_state, zip); if (!ret) { *dlen = zip_ops->output_len; memcpy(dst, zip_ops->output, *dlen); } - + kfree(zip_state); return ret; } @@ -157,7 +160,7 @@ int zip_decompress(const u8 *src, unsigned int slen, struct zip_kernel_ctx *zip_ctx) { struct zip_operation *zip_ops = NULL; - struct zip_state zip_state; + struct zip_state *zip_state; struct zip_device *zip = NULL; int ret; @@ -168,7 +171,10 @@ int zip_decompress(const u8 *src, unsigned int slen, if (!zip) return -ENODEV; - memset(&zip_state, 0, sizeof(struct zip_state)); + zip_state = kzalloc(sizeof(*zip_state), GFP_ATOMIC); + if (!zip_state) + return -ENOMEM; + zip_ops = &zip_ctx->zip_decomp; memcpy(zip_ops->input, src, slen); @@ -179,13 +185,13 @@ int zip_decompress(const u8 *src, unsigned int slen, zip_ops->input_len = slen; zip_ops->output_len = *dlen; - ret = zip_inflate(zip_ops, &zip_state, zip); + ret = zip_inflate(zip_ops, zip_state, zip); if (!ret) { *dlen = zip_ops->output_len; memcpy(dst, zip_ops->output, *dlen); } - + kfree(zip_state); return ret; } diff --git a/drivers/crypto/cavium/zip/zip_deflate.c b/drivers/crypto/cavium/zip/zip_deflate.c index 9a944b8c1e29..d7133f857d67 100644 --- a/drivers/crypto/cavium/zip/zip_deflate.c +++ b/drivers/crypto/cavium/zip/zip_deflate.c @@ -129,8 +129,8 @@ int zip_deflate(struct zip_operation *zip_ops, struct zip_state *s, /* Stats update for compression requests submitted */ atomic64_inc(&zip_dev->stats.comp_req_submit); - while (!result_ptr->s.compcode) - continue; + /* Wait for completion or error */ + zip_poll_result(result_ptr); /* Stats update for compression requests completed */ atomic64_inc(&zip_dev->stats.comp_req_complete); diff --git a/drivers/crypto/cavium/zip/zip_device.c b/drivers/crypto/cavium/zip/zip_device.c index ccf21fb91513..f174ec29ed69 100644 --- a/drivers/crypto/cavium/zip/zip_device.c +++ b/drivers/crypto/cavium/zip/zip_device.c @@ -87,12 +87,12 @@ u32 zip_load_instr(union zip_inst_s *instr, * Distribute the instructions between the enabled queues based on * the CPU id. */ - if (smp_processor_id() % 2 == 0) + if (raw_smp_processor_id() % 2 == 0) queue = 0; else queue = 1; - zip_dbg("CPU Core: %d Queue number:%d", smp_processor_id(), queue); + zip_dbg("CPU Core: %d Queue number:%d", raw_smp_processor_id(), queue); /* Take cmd buffer lock */ spin_lock(&zip_dev->iq[queue].lock); diff --git a/drivers/crypto/cavium/zip/zip_inflate.c b/drivers/crypto/cavium/zip/zip_inflate.c index 50cbdd83dbf2..7e0d73e2f89e 100644 --- a/drivers/crypto/cavium/zip/zip_inflate.c +++ b/drivers/crypto/cavium/zip/zip_inflate.c @@ -143,8 +143,8 @@ int zip_inflate(struct zip_operation *zip_ops, struct zip_state *s, /* Decompression requests submitted stats update */ atomic64_inc(&zip_dev->stats.decomp_req_submit); - while (!result_ptr->s.compcode) - continue; + /* Wait for completion or error */ + zip_poll_result(result_ptr); /* Decompression requests completed stats update */ atomic64_inc(&zip_dev->stats.decomp_req_complete); diff --git a/drivers/crypto/cavium/zip/zip_main.c b/drivers/crypto/cavium/zip/zip_main.c index 1cd8aa488185..be055b9547f6 100644 --- a/drivers/crypto/cavium/zip/zip_main.c +++ b/drivers/crypto/cavium/zip/zip_main.c @@ -113,7 +113,7 @@ struct zip_device *zip_get_device(int node) */ int zip_get_node_id(void) { - return cpu_to_node(smp_processor_id()); + return cpu_to_node(raw_smp_processor_id()); } /* Initializes the ZIP h/w sub-system */ @@ -469,6 +469,8 @@ static int zip_show_stats(struct seq_file *s, void *unused) struct zip_stats *st; for (index = 0; index < MAX_ZIP_DEVICES; index++) { + u64 pending = 0; + if (zip_dev[index]) { zip = zip_dev[index]; st = &zip->stats; @@ -476,16 +478,15 @@ static int zip_show_stats(struct seq_file *s, void *unused) /* Get all the pending requests */ for (q = 0; q < ZIP_NUM_QUEUES; q++) { val = zip_reg_read((zip->reg_base + - ZIP_DBG_COREX_STA(q))); - val = (val >> 32); - val = val & 0xffffff; - atomic64_add(val, &st->pending_req); + ZIP_DBG_QUEX_STA(q))); + pending += val >> 32 & 0xffffff; } - avg_chunk = (atomic64_read(&st->comp_in_bytes) / - atomic64_read(&st->comp_req_complete)); - avg_cr = (atomic64_read(&st->comp_in_bytes) / - atomic64_read(&st->comp_out_bytes)); + val = atomic64_read(&st->comp_req_complete); + avg_chunk = (val) ? atomic64_read(&st->comp_in_bytes) / val : 0; + + val = atomic64_read(&st->comp_out_bytes); + avg_cr = (val) ? atomic64_read(&st->comp_in_bytes) / val : 0; seq_printf(s, " ZIP Device %d Stats\n" "-----------------------------------\n" "Comp Req Submitted : \t%lld\n" @@ -513,10 +514,7 @@ static int zip_show_stats(struct seq_file *s, void *unused) (u64)atomic64_read(&st->decomp_in_bytes), (u64)atomic64_read(&st->decomp_out_bytes), (u64)atomic64_read(&st->decomp_bad_reqs), - (u64)atomic64_read(&st->pending_req)); - - /* Reset pending requests count */ - atomic64_set(&st->pending_req, 0); + pending); } } return 0; diff --git a/drivers/crypto/cavium/zip/zip_main.h b/drivers/crypto/cavium/zip/zip_main.h index 64e051f60784..e1e4fa92ce80 100644 --- a/drivers/crypto/cavium/zip/zip_main.h +++ b/drivers/crypto/cavium/zip/zip_main.h @@ -74,7 +74,6 @@ struct zip_stats { atomic64_t comp_req_complete; atomic64_t decomp_req_submit; atomic64_t decomp_req_complete; - atomic64_t pending_req; atomic64_t comp_in_bytes; atomic64_t comp_out_bytes; atomic64_t decomp_in_bytes; diff --git a/drivers/crypto/cavium/zip/zip_regs.h b/drivers/crypto/cavium/zip/zip_regs.h index d0be682305c1..874e0236c87e 100644 --- a/drivers/crypto/cavium/zip/zip_regs.h +++ b/drivers/crypto/cavium/zip/zip_regs.h @@ -443,7 +443,7 @@ union zip_corex_bist_status { static inline u64 ZIP_COREX_BIST_STATUS(u64 param1) { - if (((param1 <= 1))) + if (param1 <= 1) return 0x0520ull + (param1 & 1) * 0x8ull; pr_err("ZIP_COREX_BIST_STATUS: %llu\n", param1); return 0; @@ -537,7 +537,7 @@ union zip_dbg_corex_inst { static inline u64 ZIP_DBG_COREX_INST(u64 param1) { - if (((param1 <= 1))) + if (param1 <= 1) return 0x0640ull + (param1 & 1) * 0x8ull; pr_err("ZIP_DBG_COREX_INST: %llu\n", param1); return 0; @@ -568,7 +568,7 @@ union zip_dbg_corex_sta { static inline u64 ZIP_DBG_COREX_STA(u64 param1) { - if (((param1 <= 1))) + if (param1 <= 1) return 0x0680ull + (param1 & 1) * 0x8ull; pr_err("ZIP_DBG_COREX_STA: %llu\n", param1); return 0; @@ -599,7 +599,7 @@ union zip_dbg_quex_sta { static inline u64 ZIP_DBG_QUEX_STA(u64 param1) { - if (((param1 <= 7))) + if (param1 <= 7) return 0x1800ull + (param1 & 7) * 0x8ull; pr_err("ZIP_DBG_QUEX_STA: %llu\n", param1); return 0; @@ -817,7 +817,7 @@ union zip_msix_pbax { static inline u64 ZIP_MSIX_PBAX(u64 param1) { - if (((param1 == 0))) + if (param1 == 0) return 0x0000838000FF0000ull; pr_err("ZIP_MSIX_PBAX: %llu\n", param1); return 0; @@ -846,7 +846,7 @@ union zip_msix_vecx_addr { static inline u64 ZIP_MSIX_VECX_ADDR(u64 param1) { - if (((param1 <= 17))) + if (param1 <= 17) return 0x0000838000F00000ull + (param1 & 31) * 0x10ull; pr_err("ZIP_MSIX_VECX_ADDR: %llu\n", param1); return 0; @@ -875,7 +875,7 @@ union zip_msix_vecx_ctl { static inline u64 ZIP_MSIX_VECX_CTL(u64 param1) { - if (((param1 <= 17))) + if (param1 <= 17) return 0x0000838000F00008ull + (param1 & 31) * 0x10ull; pr_err("ZIP_MSIX_VECX_CTL: %llu\n", param1); return 0; @@ -900,7 +900,7 @@ union zip_quex_done { static inline u64 ZIP_QUEX_DONE(u64 param1) { - if (((param1 <= 7))) + if (param1 <= 7) return 0x2000ull + (param1 & 7) * 0x8ull; pr_err("ZIP_QUEX_DONE: %llu\n", param1); return 0; @@ -925,7 +925,7 @@ union zip_quex_done_ack { static inline u64 ZIP_QUEX_DONE_ACK(u64 param1) { - if (((param1 <= 7))) + if (param1 <= 7) return 0x2200ull + (param1 & 7) * 0x8ull; pr_err("ZIP_QUEX_DONE_ACK: %llu\n", param1); return 0; @@ -950,7 +950,7 @@ union zip_quex_done_ena_w1c { static inline u64 ZIP_QUEX_DONE_ENA_W1C(u64 param1) { - if (((param1 <= 7))) + if (param1 <= 7) return 0x2600ull + (param1 & 7) * 0x8ull; pr_err("ZIP_QUEX_DONE_ENA_W1C: %llu\n", param1); return 0; @@ -975,7 +975,7 @@ union zip_quex_done_ena_w1s { static inline u64 ZIP_QUEX_DONE_ENA_W1S(u64 param1) { - if (((param1 <= 7))) + if (param1 <= 7) return 0x2400ull + (param1 & 7) * 0x8ull; pr_err("ZIP_QUEX_DONE_ENA_W1S: %llu\n", param1); return 0; @@ -1004,7 +1004,7 @@ union zip_quex_done_wait { static inline u64 ZIP_QUEX_DONE_WAIT(u64 param1) { - if (((param1 <= 7))) + if (param1 <= 7) return 0x2800ull + (param1 & 7) * 0x8ull; pr_err("ZIP_QUEX_DONE_WAIT: %llu\n", param1); return 0; @@ -1029,7 +1029,7 @@ union zip_quex_doorbell { static inline u64 ZIP_QUEX_DOORBELL(u64 param1) { - if (((param1 <= 7))) + if (param1 <= 7) return 0x4000ull + (param1 & 7) * 0x8ull; pr_err("ZIP_QUEX_DOORBELL: %llu\n", param1); return 0; @@ -1058,7 +1058,7 @@ union zip_quex_err_ena_w1c { static inline u64 ZIP_QUEX_ERR_ENA_W1C(u64 param1) { - if (((param1 <= 7))) + if (param1 <= 7) return 0x3600ull + (param1 & 7) * 0x8ull; pr_err("ZIP_QUEX_ERR_ENA_W1C: %llu\n", param1); return 0; @@ -1087,7 +1087,7 @@ union zip_quex_err_ena_w1s { static inline u64 ZIP_QUEX_ERR_ENA_W1S(u64 param1) { - if (((param1 <= 7))) + if (param1 <= 7) return 0x3400ull + (param1 & 7) * 0x8ull; pr_err("ZIP_QUEX_ERR_ENA_W1S: %llu\n", param1); return 0; @@ -1120,7 +1120,7 @@ union zip_quex_err_int { static inline u64 ZIP_QUEX_ERR_INT(u64 param1) { - if (((param1 <= 7))) + if (param1 <= 7) return 0x3000ull + (param1 & 7) * 0x8ull; pr_err("ZIP_QUEX_ERR_INT: %llu\n", param1); return 0; @@ -1150,7 +1150,7 @@ union zip_quex_err_int_w1s { static inline u64 ZIP_QUEX_ERR_INT_W1S(u64 param1) { - if (((param1 <= 7))) + if (param1 <= 7) return 0x3200ull + (param1 & 7) * 0x8ull; pr_err("ZIP_QUEX_ERR_INT_W1S: %llu\n", param1); return 0; @@ -1179,7 +1179,7 @@ union zip_quex_gcfg { static inline u64 ZIP_QUEX_GCFG(u64 param1) { - if (((param1 <= 7))) + if (param1 <= 7) return 0x1A00ull + (param1 & 7) * 0x8ull; pr_err("ZIP_QUEX_GCFG: %llu\n", param1); return 0; @@ -1204,7 +1204,7 @@ union zip_quex_map { static inline u64 ZIP_QUEX_MAP(u64 param1) { - if (((param1 <= 7))) + if (param1 <= 7) return 0x1400ull + (param1 & 7) * 0x8ull; pr_err("ZIP_QUEX_MAP: %llu\n", param1); return 0; @@ -1236,7 +1236,7 @@ union zip_quex_sbuf_addr { static inline u64 ZIP_QUEX_SBUF_ADDR(u64 param1) { - if (((param1 <= 7))) + if (param1 <= 7) return 0x1000ull + (param1 & 7) * 0x8ull; pr_err("ZIP_QUEX_SBUF_ADDR: %llu\n", param1); return 0; @@ -1276,7 +1276,7 @@ union zip_quex_sbuf_ctl { static inline u64 ZIP_QUEX_SBUF_CTL(u64 param1) { - if (((param1 <= 7))) + if (param1 <= 7) return 0x1200ull + (param1 & 7) * 0x8ull; pr_err("ZIP_QUEX_SBUF_CTL: %llu\n", param1); return 0; diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c index d95ec526587a..ff478d826d7d 100644 --- a/drivers/crypto/ccp/psp-dev.c +++ b/drivers/crypto/ccp/psp-dev.c @@ -22,11 +22,17 @@ #include <linux/delay.h> #include <linux/hw_random.h> #include <linux/ccp.h> +#include <linux/firmware.h> #include "sp-dev.h" #include "psp-dev.h" +#define SEV_VERSION_GREATER_OR_EQUAL(_maj, _min) \ + ((psp_master->api_major) >= _maj && \ + (psp_master->api_minor) >= _min) + #define DEVICE_NAME "sev" +#define SEV_FW_FILE "amd/sev.fw" static DEFINE_MUTEX(sev_cmd_mutex); static struct sev_misc_dev *misc_dev; @@ -112,6 +118,8 @@ static int sev_cmd_buffer_len(int cmd) case SEV_CMD_RECEIVE_UPDATE_DATA: return sizeof(struct sev_data_receive_update_data); case SEV_CMD_RECEIVE_UPDATE_VMSA: return sizeof(struct sev_data_receive_update_vmsa); case SEV_CMD_LAUNCH_UPDATE_SECRET: return sizeof(struct sev_data_launch_secret); + case SEV_CMD_DOWNLOAD_FIRMWARE: return sizeof(struct sev_data_download_firmware); + case SEV_CMD_GET_ID: return sizeof(struct sev_data_get_id); default: return 0; } @@ -378,6 +386,79 @@ void *psp_copy_user_blob(u64 __user uaddr, u32 len) } EXPORT_SYMBOL_GPL(psp_copy_user_blob); +static int sev_get_api_version(void) +{ + struct sev_user_data_status *status; + int error, ret; + + status = &psp_master->status_cmd_buf; + ret = sev_platform_status(status, &error); + if (ret) { + dev_err(psp_master->dev, + "SEV: failed to get status. Error: %#x\n", error); + return 1; + } + + psp_master->api_major = status->api_major; + psp_master->api_minor = status->api_minor; + psp_master->build = status->build; + + return 0; +} + +/* Don't fail if SEV FW couldn't be updated. Continue with existing SEV FW */ +static int sev_update_firmware(struct device *dev) +{ + struct sev_data_download_firmware *data; + const struct firmware *firmware; + int ret, error, order; + struct page *p; + u64 data_size; + + ret = request_firmware(&firmware, SEV_FW_FILE, dev); + if (ret < 0) + return -1; + + /* + * SEV FW expects the physical address given to it to be 32 + * byte aligned. Memory allocated has structure placed at the + * beginning followed by the firmware being passed to the SEV + * FW. Allocate enough memory for data structure + alignment + * padding + SEV FW. + */ + data_size = ALIGN(sizeof(struct sev_data_download_firmware), 32); + + order = get_order(firmware->size + data_size); + p = alloc_pages(GFP_KERNEL, order); + if (!p) { + ret = -1; + goto fw_err; + } + + /* + * Copy firmware data to a kernel allocated contiguous + * memory region. + */ + data = page_address(p); + memcpy(page_address(p) + data_size, firmware->data, firmware->size); + + data->address = __psp_pa(page_address(p) + data_size); + data->len = firmware->size; + + ret = sev_do_cmd(SEV_CMD_DOWNLOAD_FIRMWARE, data, &error); + if (ret) + dev_dbg(dev, "Failed to update SEV firmware: %#x\n", error); + else + dev_info(dev, "SEV firmware update successful\n"); + + __free_pages(p, order); + +fw_err: + release_firmware(firmware); + + return ret; +} + static int sev_ioctl_do_pek_import(struct sev_issue_cmd *argp) { struct sev_user_data_pek_cert_import input; @@ -430,6 +511,46 @@ e_free: return ret; } +static int sev_ioctl_do_get_id(struct sev_issue_cmd *argp) +{ + struct sev_data_get_id *data; + u64 data_size, user_size; + void *id_blob, *mem; + int ret; + + /* SEV GET_ID available from SEV API v0.16 and up */ + if (!SEV_VERSION_GREATER_OR_EQUAL(0, 16)) + return -ENOTSUPP; + + /* SEV FW expects the buffer it fills with the ID to be + * 8-byte aligned. Memory allocated should be enough to + * hold data structure + alignment padding + memory + * where SEV FW writes the ID. + */ + data_size = ALIGN(sizeof(struct sev_data_get_id), 8); + user_size = sizeof(struct sev_user_data_get_id); + + mem = kzalloc(data_size + user_size, GFP_KERNEL); + if (!mem) + return -ENOMEM; + + data = mem; + id_blob = mem + data_size; + + data->address = __psp_pa(id_blob); + data->len = user_size; + + ret = __sev_do_cmd_locked(SEV_CMD_GET_ID, data, &argp->error); + if (!ret) { + if (copy_to_user((void __user *)argp->data, id_blob, data->len)) + ret = -EFAULT; + } + + kfree(mem); + + return ret; +} + static int sev_ioctl_do_pdh_export(struct sev_issue_cmd *argp) { struct sev_user_data_pdh_cert_export input; @@ -567,6 +688,9 @@ static long sev_ioctl(struct file *file, unsigned int ioctl, unsigned long arg) case SEV_PDH_CERT_EXPORT: ret = sev_ioctl_do_pdh_export(&input); break; + case SEV_GET_ID: + ret = sev_ioctl_do_get_id(&input); + break; default: ret = -EINVAL; goto out; @@ -750,7 +874,6 @@ EXPORT_SYMBOL_GPL(sev_issue_cmd_external_user); void psp_pci_init(void) { - struct sev_user_data_status *status; struct sp_device *sp; int error, rc; @@ -760,6 +883,13 @@ void psp_pci_init(void) psp_master = sp->psp_data; + if (sev_get_api_version()) + goto err; + + if (SEV_VERSION_GREATER_OR_EQUAL(0, 15) && + sev_update_firmware(psp_master->dev) == 0) + sev_get_api_version(); + /* Initialize the platform */ rc = sev_platform_init(&error); if (rc) { @@ -767,16 +897,9 @@ void psp_pci_init(void) goto err; } - /* Display SEV firmware version */ - status = &psp_master->status_cmd_buf; - rc = sev_platform_status(status, &error); - if (rc) { - dev_err(sp->dev, "SEV: failed to get status error %#x\n", error); - goto err; - } + dev_info(sp->dev, "SEV API:%d.%d build:%d\n", psp_master->api_major, + psp_master->api_minor, psp_master->build); - dev_info(sp->dev, "SEV API:%d.%d build:%d\n", status->api_major, - status->api_minor, status->build); return; err: diff --git a/drivers/crypto/ccp/psp-dev.h b/drivers/crypto/ccp/psp-dev.h index c81f0b11287a..c7e9098a233c 100644 --- a/drivers/crypto/ccp/psp-dev.h +++ b/drivers/crypto/ccp/psp-dev.h @@ -78,6 +78,10 @@ struct psp_device { struct sev_misc_dev *sev_misc; struct sev_user_data_status status_cmd_buf; struct sev_data_init init_cmd_buf; + + u8 api_major; + u8 api_minor; + u8 build; }; #endif /* __PSP_DEV_H */ diff --git a/drivers/crypto/ccree/cc_cipher.c b/drivers/crypto/ccree/cc_cipher.c index df98f7afe645..d2810c183b73 100644 --- a/drivers/crypto/ccree/cc_cipher.c +++ b/drivers/crypto/ccree/cc_cipher.c @@ -42,6 +42,7 @@ struct cc_cipher_ctx { int cipher_mode; int flow_mode; unsigned int flags; + bool hw_key; struct cc_user_key_info user; struct cc_hw_key_info hw; struct crypto_shash *shash_tfm; @@ -49,6 +50,13 @@ struct cc_cipher_ctx { static void cc_cipher_complete(struct device *dev, void *cc_req, int err); +static inline bool cc_is_hw_key(struct crypto_tfm *tfm) +{ + struct cc_cipher_ctx *ctx_p = crypto_tfm_ctx(tfm); + + return ctx_p->hw_key; +} + static int validate_keys_sizes(struct cc_cipher_ctx *ctx_p, u32 size) { switch (ctx_p->flow_mode) { @@ -211,7 +219,7 @@ struct tdes_keys { u8 key3[DES_KEY_SIZE]; }; -static enum cc_hw_crypto_key hw_key_to_cc_hw_key(int slot_num) +static enum cc_hw_crypto_key cc_slot_to_hw_key(int slot_num) { switch (slot_num) { case 0: @@ -226,69 +234,100 @@ static enum cc_hw_crypto_key hw_key_to_cc_hw_key(int slot_num) return END_OF_KEYS; } -static int cc_cipher_setkey(struct crypto_skcipher *sktfm, const u8 *key, - unsigned int keylen) +static int cc_cipher_sethkey(struct crypto_skcipher *sktfm, const u8 *key, + unsigned int keylen) { struct crypto_tfm *tfm = crypto_skcipher_tfm(sktfm); struct cc_cipher_ctx *ctx_p = crypto_tfm_ctx(tfm); struct device *dev = drvdata_to_dev(ctx_p->drvdata); - u32 tmp[DES3_EDE_EXPKEY_WORDS]; - struct cc_crypto_alg *cc_alg = - container_of(tfm->__crt_alg, struct cc_crypto_alg, - skcipher_alg.base); - unsigned int max_key_buf_size = cc_alg->skcipher_alg.max_keysize; + struct cc_hkey_info hki; - dev_dbg(dev, "Setting key in context @%p for %s. keylen=%u\n", + dev_dbg(dev, "Setting HW key in context @%p for %s. keylen=%u\n", ctx_p, crypto_tfm_alg_name(tfm), keylen); dump_byte_array("key", (u8 *)key, keylen); /* STAT_PHASE_0: Init and sanity checks */ + /* This check the size of the hardware key token */ + if (keylen != sizeof(hki)) { + dev_err(dev, "Unsupported HW key size %d.\n", keylen); + crypto_tfm_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); + return -EINVAL; + } + + if (ctx_p->flow_mode != S_DIN_to_AES) { + dev_err(dev, "HW key not supported for non-AES flows\n"); + return -EINVAL; + } + + memcpy(&hki, key, keylen); + + /* The real key len for crypto op is the size of the HW key + * referenced by the HW key slot, not the hardware key token + */ + keylen = hki.keylen; + if (validate_keys_sizes(ctx_p, keylen)) { dev_err(dev, "Unsupported key size %d.\n", keylen); crypto_tfm_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); return -EINVAL; } - if (cc_is_hw_key(tfm)) { - /* setting HW key slots */ - struct arm_hw_key_info *hki = (struct arm_hw_key_info *)key; + ctx_p->hw.key1_slot = cc_slot_to_hw_key(hki.hw_key1); + if (ctx_p->hw.key1_slot == END_OF_KEYS) { + dev_err(dev, "Unsupported hw key1 number (%d)\n", hki.hw_key1); + return -EINVAL; + } - if (ctx_p->flow_mode != S_DIN_to_AES) { - dev_err(dev, "HW key not supported for non-AES flows\n"); + if (ctx_p->cipher_mode == DRV_CIPHER_XTS || + ctx_p->cipher_mode == DRV_CIPHER_ESSIV || + ctx_p->cipher_mode == DRV_CIPHER_BITLOCKER) { + if (hki.hw_key1 == hki.hw_key2) { + dev_err(dev, "Illegal hw key numbers (%d,%d)\n", + hki.hw_key1, hki.hw_key2); return -EINVAL; } - - ctx_p->hw.key1_slot = hw_key_to_cc_hw_key(hki->hw_key1); - if (ctx_p->hw.key1_slot == END_OF_KEYS) { - dev_err(dev, "Unsupported hw key1 number (%d)\n", - hki->hw_key1); + ctx_p->hw.key2_slot = cc_slot_to_hw_key(hki.hw_key2); + if (ctx_p->hw.key2_slot == END_OF_KEYS) { + dev_err(dev, "Unsupported hw key2 number (%d)\n", + hki.hw_key2); return -EINVAL; } + } - if (ctx_p->cipher_mode == DRV_CIPHER_XTS || - ctx_p->cipher_mode == DRV_CIPHER_ESSIV || - ctx_p->cipher_mode == DRV_CIPHER_BITLOCKER) { - if (hki->hw_key1 == hki->hw_key2) { - dev_err(dev, "Illegal hw key numbers (%d,%d)\n", - hki->hw_key1, hki->hw_key2); - return -EINVAL; - } - ctx_p->hw.key2_slot = - hw_key_to_cc_hw_key(hki->hw_key2); - if (ctx_p->hw.key2_slot == END_OF_KEYS) { - dev_err(dev, "Unsupported hw key2 number (%d)\n", - hki->hw_key2); - return -EINVAL; - } - } + ctx_p->keylen = keylen; + ctx_p->hw_key = true; + dev_dbg(dev, "cc_is_hw_key ret 0"); + + return 0; +} + +static int cc_cipher_setkey(struct crypto_skcipher *sktfm, const u8 *key, + unsigned int keylen) +{ + struct crypto_tfm *tfm = crypto_skcipher_tfm(sktfm); + struct cc_cipher_ctx *ctx_p = crypto_tfm_ctx(tfm); + struct device *dev = drvdata_to_dev(ctx_p->drvdata); + u32 tmp[DES3_EDE_EXPKEY_WORDS]; + struct cc_crypto_alg *cc_alg = + container_of(tfm->__crt_alg, struct cc_crypto_alg, + skcipher_alg.base); + unsigned int max_key_buf_size = cc_alg->skcipher_alg.max_keysize; + + dev_dbg(dev, "Setting key in context @%p for %s. keylen=%u\n", + ctx_p, crypto_tfm_alg_name(tfm), keylen); + dump_byte_array("key", (u8 *)key, keylen); - ctx_p->keylen = keylen; - dev_dbg(dev, "cc_is_hw_key ret 0"); + /* STAT_PHASE_0: Init and sanity checks */ - return 0; + if (validate_keys_sizes(ctx_p, keylen)) { + dev_err(dev, "Unsupported key size %d.\n", keylen); + crypto_tfm_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); + return -EINVAL; } + ctx_p->hw_key = false; + /* * Verify DES weak keys * Note that we're dropping the expanded key since the @@ -735,6 +774,241 @@ static int cc_cipher_decrypt(struct skcipher_request *req) /* Block cipher alg */ static const struct cc_alg_template skcipher_algs[] = { { + .name = "xts(paes)", + .driver_name = "xts-paes-ccree", + .blocksize = AES_BLOCK_SIZE, + .template_skcipher = { + .setkey = cc_cipher_sethkey, + .encrypt = cc_cipher_encrypt, + .decrypt = cc_cipher_decrypt, + .min_keysize = CC_HW_KEY_SIZE, + .max_keysize = CC_HW_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + }, + .cipher_mode = DRV_CIPHER_XTS, + .flow_mode = S_DIN_to_AES, + .min_hw_rev = CC_HW_REV_630, + }, + { + .name = "xts512(paes)", + .driver_name = "xts-paes-du512-ccree", + .blocksize = AES_BLOCK_SIZE, + .template_skcipher = { + .setkey = cc_cipher_sethkey, + .encrypt = cc_cipher_encrypt, + .decrypt = cc_cipher_decrypt, + .min_keysize = CC_HW_KEY_SIZE, + .max_keysize = CC_HW_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + }, + .cipher_mode = DRV_CIPHER_XTS, + .flow_mode = S_DIN_to_AES, + .data_unit = 512, + .min_hw_rev = CC_HW_REV_712, + }, + { + .name = "xts4096(paes)", + .driver_name = "xts-paes-du4096-ccree", + .blocksize = AES_BLOCK_SIZE, + .template_skcipher = { + .setkey = cc_cipher_sethkey, + .encrypt = cc_cipher_encrypt, + .decrypt = cc_cipher_decrypt, + .min_keysize = CC_HW_KEY_SIZE, + .max_keysize = CC_HW_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + }, + .cipher_mode = DRV_CIPHER_XTS, + .flow_mode = S_DIN_to_AES, + .data_unit = 4096, + .min_hw_rev = CC_HW_REV_712, + }, + { + .name = "essiv(paes)", + .driver_name = "essiv-paes-ccree", + .blocksize = AES_BLOCK_SIZE, + .template_skcipher = { + .setkey = cc_cipher_sethkey, + .encrypt = cc_cipher_encrypt, + .decrypt = cc_cipher_decrypt, + .min_keysize = CC_HW_KEY_SIZE, + .max_keysize = CC_HW_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + }, + .cipher_mode = DRV_CIPHER_ESSIV, + .flow_mode = S_DIN_to_AES, + .min_hw_rev = CC_HW_REV_712, + }, + { + .name = "essiv512(paes)", + .driver_name = "essiv-paes-du512-ccree", + .blocksize = AES_BLOCK_SIZE, + .template_skcipher = { + .setkey = cc_cipher_sethkey, + .encrypt = cc_cipher_encrypt, + .decrypt = cc_cipher_decrypt, + .min_keysize = CC_HW_KEY_SIZE, + .max_keysize = CC_HW_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + }, + .cipher_mode = DRV_CIPHER_ESSIV, + .flow_mode = S_DIN_to_AES, + .data_unit = 512, + .min_hw_rev = CC_HW_REV_712, + }, + { + .name = "essiv4096(paes)", + .driver_name = "essiv-paes-du4096-ccree", + .blocksize = AES_BLOCK_SIZE, + .template_skcipher = { + .setkey = cc_cipher_sethkey, + .encrypt = cc_cipher_encrypt, + .decrypt = cc_cipher_decrypt, + .min_keysize = CC_HW_KEY_SIZE, + .max_keysize = CC_HW_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + }, + .cipher_mode = DRV_CIPHER_ESSIV, + .flow_mode = S_DIN_to_AES, + .data_unit = 4096, + .min_hw_rev = CC_HW_REV_712, + }, + { + .name = "bitlocker(paes)", + .driver_name = "bitlocker-paes-ccree", + .blocksize = AES_BLOCK_SIZE, + .template_skcipher = { + .setkey = cc_cipher_sethkey, + .encrypt = cc_cipher_encrypt, + .decrypt = cc_cipher_decrypt, + .min_keysize = CC_HW_KEY_SIZE, + .max_keysize = CC_HW_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + }, + .cipher_mode = DRV_CIPHER_BITLOCKER, + .flow_mode = S_DIN_to_AES, + .min_hw_rev = CC_HW_REV_712, + }, + { + .name = "bitlocker512(paes)", + .driver_name = "bitlocker-paes-du512-ccree", + .blocksize = AES_BLOCK_SIZE, + .template_skcipher = { + .setkey = cc_cipher_sethkey, + .encrypt = cc_cipher_encrypt, + .decrypt = cc_cipher_decrypt, + .min_keysize = CC_HW_KEY_SIZE, + .max_keysize = CC_HW_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + }, + .cipher_mode = DRV_CIPHER_BITLOCKER, + .flow_mode = S_DIN_to_AES, + .data_unit = 512, + .min_hw_rev = CC_HW_REV_712, + }, + { + .name = "bitlocker4096(paes)", + .driver_name = "bitlocker-paes-du4096-ccree", + .blocksize = AES_BLOCK_SIZE, + .template_skcipher = { + .setkey = cc_cipher_sethkey, + .encrypt = cc_cipher_encrypt, + .decrypt = cc_cipher_decrypt, + .min_keysize = CC_HW_KEY_SIZE, + .max_keysize = CC_HW_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + }, + .cipher_mode = DRV_CIPHER_BITLOCKER, + .flow_mode = S_DIN_to_AES, + .data_unit = 4096, + .min_hw_rev = CC_HW_REV_712, + }, + { + .name = "ecb(paes)", + .driver_name = "ecb-paes-ccree", + .blocksize = AES_BLOCK_SIZE, + .type = CRYPTO_ALG_TYPE_ABLKCIPHER, + .template_skcipher = { + .setkey = cc_cipher_sethkey, + .encrypt = cc_cipher_encrypt, + .decrypt = cc_cipher_decrypt, + .min_keysize = CC_HW_KEY_SIZE, + .max_keysize = CC_HW_KEY_SIZE, + .ivsize = 0, + }, + .cipher_mode = DRV_CIPHER_ECB, + .flow_mode = S_DIN_to_AES, + .min_hw_rev = CC_HW_REV_712, + }, + { + .name = "cbc(paes)", + .driver_name = "cbc-paes-ccree", + .blocksize = AES_BLOCK_SIZE, + .type = CRYPTO_ALG_TYPE_ABLKCIPHER, + .template_skcipher = { + .setkey = cc_cipher_sethkey, + .encrypt = cc_cipher_encrypt, + .decrypt = cc_cipher_decrypt, + .min_keysize = CC_HW_KEY_SIZE, + .max_keysize = CC_HW_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + }, + .cipher_mode = DRV_CIPHER_CBC, + .flow_mode = S_DIN_to_AES, + .min_hw_rev = CC_HW_REV_712, + }, + { + .name = "ofb(paes)", + .driver_name = "ofb-paes-ccree", + .blocksize = AES_BLOCK_SIZE, + .type = CRYPTO_ALG_TYPE_ABLKCIPHER, + .template_skcipher = { + .setkey = cc_cipher_sethkey, + .encrypt = cc_cipher_encrypt, + .decrypt = cc_cipher_decrypt, + .min_keysize = CC_HW_KEY_SIZE, + .max_keysize = CC_HW_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + }, + .cipher_mode = DRV_CIPHER_OFB, + .flow_mode = S_DIN_to_AES, + .min_hw_rev = CC_HW_REV_712, + }, + { + .name = "cts1(cbc(paes))", + .driver_name = "cts1-cbc-paes-ccree", + .blocksize = AES_BLOCK_SIZE, + .type = CRYPTO_ALG_TYPE_ABLKCIPHER, + .template_skcipher = { + .setkey = cc_cipher_sethkey, + .encrypt = cc_cipher_encrypt, + .decrypt = cc_cipher_decrypt, + .min_keysize = CC_HW_KEY_SIZE, + .max_keysize = CC_HW_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + }, + .cipher_mode = DRV_CIPHER_CBC_CTS, + .flow_mode = S_DIN_to_AES, + .min_hw_rev = CC_HW_REV_712, + }, + { + .name = "ctr(paes)", + .driver_name = "ctr-paes-ccree", + .blocksize = 1, + .type = CRYPTO_ALG_TYPE_ABLKCIPHER, + .template_skcipher = { + .setkey = cc_cipher_sethkey, + .encrypt = cc_cipher_encrypt, + .decrypt = cc_cipher_decrypt, + .min_keysize = CC_HW_KEY_SIZE, + .max_keysize = CC_HW_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + }, + .cipher_mode = DRV_CIPHER_CTR, + .flow_mode = S_DIN_to_AES, + .min_hw_rev = CC_HW_REV_712, + }, + { .name = "xts(aes)", .driver_name = "xts-aes-ccree", .blocksize = AES_BLOCK_SIZE, diff --git a/drivers/crypto/ccree/cc_cipher.h b/drivers/crypto/ccree/cc_cipher.h index 2a2a6f46c515..68444cfa936b 100644 --- a/drivers/crypto/ccree/cc_cipher.h +++ b/drivers/crypto/ccree/cc_cipher.h @@ -13,18 +13,6 @@ #include "cc_driver.h" #include "cc_buffer_mgr.h" -/* Crypto cipher flags */ -#define CC_CRYPTO_CIPHER_KEY_KFDE0 BIT(0) -#define CC_CRYPTO_CIPHER_KEY_KFDE1 BIT(1) -#define CC_CRYPTO_CIPHER_KEY_KFDE2 BIT(2) -#define CC_CRYPTO_CIPHER_KEY_KFDE3 BIT(3) -#define CC_CRYPTO_CIPHER_DU_SIZE_512B BIT(4) - -#define CC_CRYPTO_CIPHER_KEY_KFDE_MASK (CC_CRYPTO_CIPHER_KEY_KFDE0 | \ - CC_CRYPTO_CIPHER_KEY_KFDE1 | \ - CC_CRYPTO_CIPHER_KEY_KFDE2 | \ - CC_CRYPTO_CIPHER_KEY_KFDE3) - struct cipher_req_ctx { struct async_gen_req_ctx gen_ctx; enum cc_req_dma_buf_type dma_buf_type; @@ -42,18 +30,12 @@ int cc_cipher_alloc(struct cc_drvdata *drvdata); int cc_cipher_free(struct cc_drvdata *drvdata); -struct arm_hw_key_info { - int hw_key1; - int hw_key2; -}; +struct cc_hkey_info { + u16 keylen; + u8 hw_key1; + u8 hw_key2; +} __packed; -/* - * This is a stub function that will replaced when we - * implement secure keys - */ -static inline bool cc_is_hw_key(struct crypto_tfm *tfm) -{ - return false; -} +#define CC_HW_KEY_SIZE sizeof(struct cc_hkey_info) #endif /*__CC_CIPHER_H__*/ diff --git a/drivers/crypto/ccree/cc_debugfs.c b/drivers/crypto/ccree/cc_debugfs.c index 08f8db489cf0..5ca184e42483 100644 --- a/drivers/crypto/ccree/cc_debugfs.c +++ b/drivers/crypto/ccree/cc_debugfs.c @@ -26,7 +26,8 @@ struct cc_debugfs_ctx { static struct dentry *cc_debugfs_dir; static struct debugfs_reg32 debug_regs[] = { - CC_DEBUG_REG(HOST_SIGNATURE), + { .name = "SIGNATURE" }, /* Must be 0th */ + { .name = "VERSION" }, /* Must be 1st */ CC_DEBUG_REG(HOST_IRR), CC_DEBUG_REG(HOST_POWER_DOWN_EN), CC_DEBUG_REG(AXIM_MON_ERR), @@ -34,7 +35,6 @@ static struct debugfs_reg32 debug_regs[] = { CC_DEBUG_REG(HOST_IMR), CC_DEBUG_REG(AXIM_CFG), CC_DEBUG_REG(AXIM_CACHE_PARAMS), - CC_DEBUG_REG(HOST_VERSION), CC_DEBUG_REG(GPR_HOST), CC_DEBUG_REG(AXIM_MON_COMP), }; @@ -58,6 +58,9 @@ int cc_debugfs_init(struct cc_drvdata *drvdata) struct debugfs_regset32 *regset; struct dentry *file; + debug_regs[0].offset = drvdata->sig_offset; + debug_regs[1].offset = drvdata->ver_offset; + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; diff --git a/drivers/crypto/ccree/cc_driver.c b/drivers/crypto/ccree/cc_driver.c index 89ce013ae093..bd974fef05e4 100644 --- a/drivers/crypto/ccree/cc_driver.c +++ b/drivers/crypto/ccree/cc_driver.c @@ -168,14 +168,14 @@ int init_cc_regs(struct cc_drvdata *drvdata, bool is_probe) val = cc_ioread(drvdata, CC_REG(AXIM_CACHE_PARAMS)); if (is_probe) - dev_info(dev, "Cache params previous: 0x%08X\n", val); + dev_dbg(dev, "Cache params previous: 0x%08X\n", val); cc_iowrite(drvdata, CC_REG(AXIM_CACHE_PARAMS), cache_params); val = cc_ioread(drvdata, CC_REG(AXIM_CACHE_PARAMS)); if (is_probe) - dev_info(dev, "Cache params current: 0x%08X (expect: 0x%08X)\n", - val, cache_params); + dev_dbg(dev, "Cache params current: 0x%08X (expect: 0x%08X)\n", + val, cache_params); return 0; } @@ -190,6 +190,7 @@ static int init_cc_resources(struct platform_device *plat_dev) u64 dma_mask; const struct cc_hw_data *hw_rev; const struct of_device_id *dev_id; + struct clk *clk; int rc = 0; new_drvdata = devm_kzalloc(dev, sizeof(*new_drvdata), GFP_KERNEL); @@ -207,15 +208,36 @@ static int init_cc_resources(struct platform_device *plat_dev) if (hw_rev->rev >= CC_HW_REV_712) { new_drvdata->hash_len_sz = HASH_LEN_SIZE_712; new_drvdata->axim_mon_offset = CC_REG(AXIM_MON_COMP); + new_drvdata->sig_offset = CC_REG(HOST_SIGNATURE_712); + new_drvdata->ver_offset = CC_REG(HOST_VERSION_712); } else { new_drvdata->hash_len_sz = HASH_LEN_SIZE_630; new_drvdata->axim_mon_offset = CC_REG(AXIM_MON_COMP8); + new_drvdata->sig_offset = CC_REG(HOST_SIGNATURE_630); + new_drvdata->ver_offset = CC_REG(HOST_VERSION_630); } platform_set_drvdata(plat_dev, new_drvdata); new_drvdata->plat_dev = plat_dev; - new_drvdata->clk = of_clk_get(np, 0); + clk = devm_clk_get(dev, NULL); + if (IS_ERR(clk)) + switch (PTR_ERR(clk)) { + /* Clock is optional so this might be fine */ + case -ENOENT: + break; + + /* Clock not available, let's try again soon */ + case -EPROBE_DEFER: + return -EPROBE_DEFER; + + default: + dev_err(dev, "Error getting clock: %ld\n", + PTR_ERR(clk)); + return PTR_ERR(clk); + } + new_drvdata->clk = clk; + new_drvdata->coherent = of_dma_is_coherent(np); /* Get device resources */ @@ -265,7 +287,7 @@ static int init_cc_resources(struct platform_device *plat_dev) } if (rc) { - dev_err(dev, "Failed in dma_set_mask, mask=%pad\n", &dma_mask); + dev_err(dev, "Failed in dma_set_mask, mask=%llx\n", dma_mask); return rc; } @@ -276,7 +298,7 @@ static int init_cc_resources(struct platform_device *plat_dev) } /* Verify correct mapping */ - signature_val = cc_ioread(new_drvdata, CC_REG(HOST_SIGNATURE)); + signature_val = cc_ioread(new_drvdata, new_drvdata->sig_offset); if (signature_val != hw_rev->sig) { dev_err(dev, "Invalid CC signature: SIGNATURE=0x%08X != expected=0x%08X\n", signature_val, hw_rev->sig); @@ -287,7 +309,7 @@ static int init_cc_resources(struct platform_device *plat_dev) /* Display HW versions */ dev_info(dev, "ARM CryptoCell %s Driver: HW version 0x%08X, Driver version %s\n", - hw_rev->name, cc_ioread(new_drvdata, CC_REG(HOST_VERSION)), + hw_rev->name, cc_ioread(new_drvdata, new_drvdata->ver_offset), DRV_MODULE_VERSION); rc = init_cc_regs(new_drvdata, true); diff --git a/drivers/crypto/ccree/cc_driver.h b/drivers/crypto/ccree/cc_driver.h index 2048fdeb9579..95f82b2d1e70 100644 --- a/drivers/crypto/ccree/cc_driver.h +++ b/drivers/crypto/ccree/cc_driver.h @@ -129,6 +129,8 @@ struct cc_drvdata { enum cc_hw_rev hw_rev; u32 hash_len_sz; u32 axim_mon_offset; + u32 sig_offset; + u32 ver_offset; }; struct cc_crypto_alg { diff --git a/drivers/crypto/ccree/cc_host_regs.h b/drivers/crypto/ccree/cc_host_regs.h index f51001898ca1..616b2e1c41ba 100644 --- a/drivers/crypto/ccree/cc_host_regs.h +++ b/drivers/crypto/ccree/cc_host_regs.h @@ -45,7 +45,8 @@ #define CC_HOST_ICR_DSCRPTR_WATERMARK_QUEUE0_CLEAR_BIT_SIZE 0x1UL #define CC_HOST_ICR_AXIM_COMP_INT_CLEAR_BIT_SHIFT 0x17UL #define CC_HOST_ICR_AXIM_COMP_INT_CLEAR_BIT_SIZE 0x1UL -#define CC_HOST_SIGNATURE_REG_OFFSET 0xA24UL +#define CC_HOST_SIGNATURE_712_REG_OFFSET 0xA24UL +#define CC_HOST_SIGNATURE_630_REG_OFFSET 0xAC8UL #define CC_HOST_SIGNATURE_VALUE_BIT_SHIFT 0x0UL #define CC_HOST_SIGNATURE_VALUE_BIT_SIZE 0x20UL #define CC_HOST_BOOT_REG_OFFSET 0xA28UL @@ -105,7 +106,8 @@ #define CC_HOST_BOOT_ONLY_ENCRYPT_LOCAL_BIT_SIZE 0x1UL #define CC_HOST_BOOT_AES_EXISTS_LOCAL_BIT_SHIFT 0x1EUL #define CC_HOST_BOOT_AES_EXISTS_LOCAL_BIT_SIZE 0x1UL -#define CC_HOST_VERSION_REG_OFFSET 0xA40UL +#define CC_HOST_VERSION_712_REG_OFFSET 0xA40UL +#define CC_HOST_VERSION_630_REG_OFFSET 0xAD8UL #define CC_HOST_VERSION_VALUE_BIT_SHIFT 0x0UL #define CC_HOST_VERSION_VALUE_BIT_SIZE 0x20UL #define CC_HOST_KFDE0_VALID_REG_OFFSET 0xA60UL diff --git a/drivers/crypto/chelsio/chcr_algo.c b/drivers/crypto/chelsio/chcr_algo.c index 59fe6631e73e..b916c4eb608c 100644 --- a/drivers/crypto/chelsio/chcr_algo.c +++ b/drivers/crypto/chelsio/chcr_algo.c @@ -203,13 +203,8 @@ static inline void chcr_handle_aead_resp(struct aead_request *req, int err) { struct chcr_aead_reqctx *reqctx = aead_request_ctx(req); - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct uld_ctx *u_ctx = ULD_CTX(a_ctx(tfm)); - chcr_aead_dma_unmap(&u_ctx->lldi.pdev->dev, req, reqctx->op); - if (reqctx->b0_dma) - dma_unmap_single(&u_ctx->lldi.pdev->dev, reqctx->b0_dma, - reqctx->b0_len, DMA_BIDIRECTIONAL); + chcr_aead_common_exit(req); if (reqctx->verify == VERIFY_SW) { chcr_verify_tag(req, input, &err); reqctx->verify = VERIFY_HW; @@ -638,7 +633,6 @@ static int chcr_sg_ent_in_wr(struct scatterlist *src, src = sg_next(src); srcskip = 0; } - if (sg_dma_len(dst) == dstskip) { dst = sg_next(dst); dstskip = 0; @@ -688,6 +682,7 @@ static int chcr_cipher_fallback(struct crypto_skcipher *cipher, int err; SKCIPHER_REQUEST_ON_STACK(subreq, cipher); + skcipher_request_set_tfm(subreq, cipher); skcipher_request_set_callback(subreq, flags, NULL, NULL); skcipher_request_set_crypt(subreq, src, dst, @@ -760,13 +755,13 @@ static struct sk_buff *create_cipher_wr(struct cipher_wr_param *wrparam) nents = sg_nents_xlen(reqctx->dstsg, wrparam->bytes, CHCR_DST_SG_SIZE, reqctx->dst_ofst); - dst_size = get_space_for_phys_dsgl(nents + 1); + dst_size = get_space_for_phys_dsgl(nents); kctx_len = roundup(ablkctx->enckey_len, 16); transhdr_len = CIPHER_TRANSHDR_SIZE(kctx_len, dst_size); nents = sg_nents_xlen(reqctx->srcsg, wrparam->bytes, CHCR_SRC_SG_SIZE, reqctx->src_ofst); - temp = reqctx->imm ? roundup(IV + wrparam->req->nbytes, 16) : - (sgl_len(nents + MIN_CIPHER_SG) * 8); + temp = reqctx->imm ? roundup(wrparam->bytes, 16) : + (sgl_len(nents) * 8); transhdr_len += temp; transhdr_len = roundup(transhdr_len, 16); skb = alloc_skb(SGE_MAX_WR_LEN, flags); @@ -788,7 +783,7 @@ static struct sk_buff *create_cipher_wr(struct cipher_wr_param *wrparam) ablkctx->ciph_mode, 0, 0, IV >> 1); chcr_req->sec_cpl.ivgen_hdrlen = FILL_SEC_CPL_IVGEN_HDRLEN(0, 0, 0, - 0, 0, dst_size); + 0, 1, dst_size); chcr_req->key_ctx.ctx_hdr = ablkctx->key_ctx_hdr; if ((reqctx->op == CHCR_DECRYPT_OP) && @@ -818,8 +813,8 @@ static struct sk_buff *create_cipher_wr(struct cipher_wr_param *wrparam) chcr_add_cipher_dst_ent(wrparam->req, phys_cpl, wrparam, wrparam->qid); atomic_inc(&adap->chcr_stats.cipher_rqst); - temp = sizeof(struct cpl_rx_phys_dsgl) + dst_size + kctx_len - +(reqctx->imm ? (IV + wrparam->bytes) : 0); + temp = sizeof(struct cpl_rx_phys_dsgl) + dst_size + kctx_len + IV + + (reqctx->imm ? (wrparam->bytes) : 0); create_wreq(c_ctx(tfm), chcr_req, &(wrparam->req->base), reqctx->imm, 0, transhdr_len, temp, ablkctx->ciph_mode == CHCR_SCMD_CIPHER_MODE_AES_CBC); @@ -1022,7 +1017,7 @@ static int chcr_update_tweak(struct ablkcipher_request *req, u8 *iv, ret = crypto_cipher_setkey(cipher, key, keylen); if (ret) goto out; - /*H/W sends the encrypted IV in dsgl when AADIVDROP bit is 0*/ + crypto_cipher_encrypt_one(cipher, iv, iv); for (i = 0; i < round8; i++) gf128mul_x8_ble((le128 *)iv, (le128 *)iv); @@ -1113,16 +1108,8 @@ static int chcr_handle_cipher_resp(struct ablkcipher_request *req, goto complete; } - if (unlikely(cxgb4_is_crypto_q_full(u_ctx->lldi.ports[0], - c_ctx(tfm)->tx_qidx))) { - if (!(req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) { - err = -EBUSY; - goto unmap; - } - - } if (!reqctx->imm) { - bytes = chcr_sg_ent_in_wr(reqctx->srcsg, reqctx->dstsg, 1, + bytes = chcr_sg_ent_in_wr(reqctx->srcsg, reqctx->dstsg, 0, CIP_SPACE_LEFT(ablkctx->enckey_len), reqctx->src_ofst, reqctx->dst_ofst); if ((bytes + reqctx->processed) >= req->nbytes) @@ -1133,11 +1120,7 @@ static int chcr_handle_cipher_resp(struct ablkcipher_request *req, /*CTR mode counter overfloa*/ bytes = req->nbytes - reqctx->processed; } - dma_sync_single_for_cpu(&ULD_CTX(c_ctx(tfm))->lldi.pdev->dev, - reqctx->iv_dma, IV, DMA_BIDIRECTIONAL); err = chcr_update_cipher_iv(req, fw6_pld, reqctx->iv); - dma_sync_single_for_device(&ULD_CTX(c_ctx(tfm))->lldi.pdev->dev, - reqctx->iv_dma, IV, DMA_BIDIRECTIONAL); if (err) goto unmap; @@ -1212,7 +1195,6 @@ static int process_cipher(struct ablkcipher_request *req, dnents = sg_nents_xlen(req->dst, req->nbytes, CHCR_DST_SG_SIZE, 0); - dnents += 1; // IV phys_dsgl = get_space_for_phys_dsgl(dnents); kctx_len = roundup(ablkctx->enckey_len, 16); transhdr_len = CIPHER_TRANSHDR_SIZE(kctx_len, phys_dsgl); @@ -1225,8 +1207,7 @@ static int process_cipher(struct ablkcipher_request *req, } if (!reqctx->imm) { - bytes = chcr_sg_ent_in_wr(req->src, req->dst, - MIN_CIPHER_SG, + bytes = chcr_sg_ent_in_wr(req->src, req->dst, 0, CIP_SPACE_LEFT(ablkctx->enckey_len), 0, 0); if ((bytes + reqctx->processed) >= req->nbytes) @@ -1293,13 +1274,14 @@ static int chcr_aes_encrypt(struct ablkcipher_request *req) { struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); struct sk_buff *skb = NULL; - int err; + int err, isfull = 0; struct uld_ctx *u_ctx = ULD_CTX(c_ctx(tfm)); if (unlikely(cxgb4_is_crypto_q_full(u_ctx->lldi.ports[0], c_ctx(tfm)->tx_qidx))) { + isfull = 1; if (!(req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) - return -EBUSY; + return -ENOSPC; } err = process_cipher(req, u_ctx->lldi.rxq_ids[c_ctx(tfm)->rx_qidx], @@ -1309,7 +1291,7 @@ static int chcr_aes_encrypt(struct ablkcipher_request *req) skb->dev = u_ctx->lldi.ports[0]; set_wr_txq(skb, CPL_PRIORITY_DATA, c_ctx(tfm)->tx_qidx); chcr_send_wr(skb); - return -EINPROGRESS; + return isfull ? -EBUSY : -EINPROGRESS; } static int chcr_aes_decrypt(struct ablkcipher_request *req) @@ -1317,12 +1299,13 @@ static int chcr_aes_decrypt(struct ablkcipher_request *req) struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); struct uld_ctx *u_ctx = ULD_CTX(c_ctx(tfm)); struct sk_buff *skb = NULL; - int err; + int err, isfull = 0; if (unlikely(cxgb4_is_crypto_q_full(u_ctx->lldi.ports[0], c_ctx(tfm)->tx_qidx))) { + isfull = 1; if (!(req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) - return -EBUSY; + return -ENOSPC; } err = process_cipher(req, u_ctx->lldi.rxq_ids[c_ctx(tfm)->rx_qidx], @@ -1332,7 +1315,7 @@ static int chcr_aes_decrypt(struct ablkcipher_request *req) skb->dev = u_ctx->lldi.ports[0]; set_wr_txq(skb, CPL_PRIORITY_DATA, c_ctx(tfm)->tx_qidx); chcr_send_wr(skb); - return -EINPROGRESS; + return isfull ? -EBUSY : -EINPROGRESS; } static int chcr_device_init(struct chcr_context *ctx) @@ -1574,14 +1557,15 @@ static int chcr_ahash_update(struct ahash_request *req) u8 remainder = 0, bs; unsigned int nbytes = req->nbytes; struct hash_wr_param params; - int error; + int error, isfull = 0; bs = crypto_tfm_alg_blocksize(crypto_ahash_tfm(rtfm)); u_ctx = ULD_CTX(h_ctx(rtfm)); if (unlikely(cxgb4_is_crypto_q_full(u_ctx->lldi.ports[0], h_ctx(rtfm)->tx_qidx))) { + isfull = 1; if (!(req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) - return -EBUSY; + return -ENOSPC; } if (nbytes + req_ctx->reqlen >= bs) { @@ -1633,7 +1617,7 @@ static int chcr_ahash_update(struct ahash_request *req) set_wr_txq(skb, CPL_PRIORITY_DATA, h_ctx(rtfm)->tx_qidx); chcr_send_wr(skb); - return -EINPROGRESS; + return isfull ? -EBUSY : -EINPROGRESS; unmap: chcr_hash_dma_unmap(&u_ctx->lldi.pdev->dev, req); return error; @@ -1710,15 +1694,16 @@ static int chcr_ahash_finup(struct ahash_request *req) struct sk_buff *skb; struct hash_wr_param params; u8 bs; - int error; + int error, isfull = 0; bs = crypto_tfm_alg_blocksize(crypto_ahash_tfm(rtfm)); u_ctx = ULD_CTX(h_ctx(rtfm)); if (unlikely(cxgb4_is_crypto_q_full(u_ctx->lldi.ports[0], h_ctx(rtfm)->tx_qidx))) { + isfull = 1; if (!(req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) - return -EBUSY; + return -ENOSPC; } chcr_init_hctx_per_wr(req_ctx); error = chcr_hash_dma_map(&u_ctx->lldi.pdev->dev, req); @@ -1777,7 +1762,7 @@ static int chcr_ahash_finup(struct ahash_request *req) set_wr_txq(skb, CPL_PRIORITY_DATA, h_ctx(rtfm)->tx_qidx); chcr_send_wr(skb); - return -EINPROGRESS; + return isfull ? -EBUSY : -EINPROGRESS; unmap: chcr_hash_dma_unmap(&u_ctx->lldi.pdev->dev, req); return error; @@ -1791,7 +1776,7 @@ static int chcr_ahash_digest(struct ahash_request *req) struct sk_buff *skb; struct hash_wr_param params; u8 bs; - int error; + int error, isfull = 0; rtfm->init(req); bs = crypto_tfm_alg_blocksize(crypto_ahash_tfm(rtfm)); @@ -1799,8 +1784,9 @@ static int chcr_ahash_digest(struct ahash_request *req) u_ctx = ULD_CTX(h_ctx(rtfm)); if (unlikely(cxgb4_is_crypto_q_full(u_ctx->lldi.ports[0], h_ctx(rtfm)->tx_qidx))) { + isfull = 1; if (!(req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) - return -EBUSY; + return -ENOSPC; } chcr_init_hctx_per_wr(req_ctx); @@ -1856,7 +1842,7 @@ static int chcr_ahash_digest(struct ahash_request *req) skb->dev = u_ctx->lldi.ports[0]; set_wr_txq(skb, CPL_PRIORITY_DATA, h_ctx(rtfm)->tx_qidx); chcr_send_wr(skb); - return -EINPROGRESS; + return isfull ? -EBUSY : -EINPROGRESS; unmap: chcr_hash_dma_unmap(&u_ctx->lldi.pdev->dev, req); return error; @@ -1875,11 +1861,6 @@ static int chcr_ahash_continue(struct ahash_request *req) bs = crypto_tfm_alg_blocksize(crypto_ahash_tfm(rtfm)); u_ctx = ULD_CTX(h_ctx(rtfm)); - if (unlikely(cxgb4_is_crypto_q_full(u_ctx->lldi.ports[0], - h_ctx(rtfm)->tx_qidx))) { - if (!(req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) - return -EBUSY; - } get_alg_config(¶ms.alg_prm, crypto_ahash_digestsize(rtfm)); params.kctx_len = roundup(params.alg_prm.result_size, 16); if (is_hmac(crypto_ahash_tfm(rtfm))) { @@ -2192,22 +2173,35 @@ static void chcr_hmac_cra_exit(struct crypto_tfm *tfm) } } -static int chcr_aead_common_init(struct aead_request *req, - unsigned short op_type) +inline void chcr_aead_common_exit(struct aead_request *req) +{ + struct chcr_aead_reqctx *reqctx = aead_request_ctx(req); + struct crypto_aead *tfm = crypto_aead_reqtfm(req); + struct uld_ctx *u_ctx = ULD_CTX(a_ctx(tfm)); + + chcr_aead_dma_unmap(&u_ctx->lldi.pdev->dev, req, reqctx->op); +} + +static int chcr_aead_common_init(struct aead_request *req) { struct crypto_aead *tfm = crypto_aead_reqtfm(req); struct chcr_aead_ctx *aeadctx = AEAD_CTX(a_ctx(tfm)); struct chcr_aead_reqctx *reqctx = aead_request_ctx(req); - int error = -EINVAL; unsigned int authsize = crypto_aead_authsize(tfm); + int error = -EINVAL; /* validate key size */ if (aeadctx->enckey_len == 0) goto err; - if (op_type && req->cryptlen < authsize) + if (reqctx->op && req->cryptlen < authsize) goto err; + if (reqctx->b0_len) + reqctx->scratch_pad = reqctx->iv + IV; + else + reqctx->scratch_pad = NULL; + error = chcr_aead_dma_map(&ULD_CTX(a_ctx(tfm))->lldi.pdev->dev, req, - op_type); + reqctx->op); if (error) { error = -ENOMEM; goto err; @@ -2244,7 +2238,7 @@ static int chcr_aead_fallback(struct aead_request *req, unsigned short op_type) aead_request_set_tfm(subreq, aeadctx->sw_cipher); aead_request_set_callback(subreq, req->base.flags, req->base.complete, req->base.data); - aead_request_set_crypt(subreq, req->src, req->dst, req->cryptlen, + aead_request_set_crypt(subreq, req->src, req->dst, req->cryptlen, req->iv); aead_request_set_ad(subreq, req->assoclen); return op_type ? crypto_aead_decrypt(subreq) : @@ -2253,8 +2247,7 @@ static int chcr_aead_fallback(struct aead_request *req, unsigned short op_type) static struct sk_buff *create_authenc_wr(struct aead_request *req, unsigned short qid, - int size, - unsigned short op_type) + int size) { struct crypto_aead *tfm = crypto_aead_reqtfm(req); struct chcr_aead_ctx *aeadctx = AEAD_CTX(a_ctx(tfm)); @@ -2278,18 +2271,20 @@ static struct sk_buff *create_authenc_wr(struct aead_request *req, if (req->cryptlen == 0) return NULL; - reqctx->b0_dma = 0; + reqctx->b0_len = 0; + error = chcr_aead_common_init(req); + if (error) + return ERR_PTR(error); + if (subtype == CRYPTO_ALG_SUB_TYPE_CBC_NULL || - subtype == CRYPTO_ALG_SUB_TYPE_CTR_NULL) { + subtype == CRYPTO_ALG_SUB_TYPE_CTR_NULL) { null = 1; assoclen = 0; + reqctx->aad_nents = 0; } - error = chcr_aead_common_init(req, op_type); - if (error) - return ERR_PTR(error); dnents = sg_nents_xlen(req->dst, assoclen, CHCR_DST_SG_SIZE, 0); dnents += sg_nents_xlen(req->dst, req->cryptlen + - (op_type ? -authsize : authsize), CHCR_DST_SG_SIZE, + (reqctx->op ? -authsize : authsize), CHCR_DST_SG_SIZE, req->assoclen); dnents += MIN_AUTH_SG; // For IV @@ -2306,11 +2301,10 @@ static struct sk_buff *create_authenc_wr(struct aead_request *req, transhdr_len = roundup(transhdr_len, 16); if (chcr_aead_need_fallback(req, dnents, T6_MAX_AAD_SIZE, - transhdr_len, op_type)) { + transhdr_len, reqctx->op)) { atomic_inc(&adap->chcr_stats.fallback); - chcr_aead_dma_unmap(&ULD_CTX(a_ctx(tfm))->lldi.pdev->dev, req, - op_type); - return ERR_PTR(chcr_aead_fallback(req, op_type)); + chcr_aead_common_exit(req); + return ERR_PTR(chcr_aead_fallback(req, reqctx->op)); } skb = alloc_skb(SGE_MAX_WR_LEN, flags); if (!skb) { @@ -2320,7 +2314,7 @@ static struct sk_buff *create_authenc_wr(struct aead_request *req, chcr_req = __skb_put_zero(skb, transhdr_len); - temp = (op_type == CHCR_ENCRYPT_OP) ? 0 : authsize; + temp = (reqctx->op == CHCR_ENCRYPT_OP) ? 0 : authsize; /* * Input order is AAD,IV and Payload. where IV should be included as @@ -2344,8 +2338,8 @@ static struct sk_buff *create_authenc_wr(struct aead_request *req, temp = CHCR_SCMD_CIPHER_MODE_AES_CTR; else temp = CHCR_SCMD_CIPHER_MODE_AES_CBC; - chcr_req->sec_cpl.seqno_numivs = FILL_SEC_CPL_SCMD0_SEQNO(op_type, - (op_type == CHCR_ENCRYPT_OP) ? 1 : 0, + chcr_req->sec_cpl.seqno_numivs = FILL_SEC_CPL_SCMD0_SEQNO(reqctx->op, + (reqctx->op == CHCR_ENCRYPT_OP) ? 1 : 0, temp, actx->auth_mode, aeadctx->hmac_ctrl, IV >> 1); @@ -2353,7 +2347,7 @@ static struct sk_buff *create_authenc_wr(struct aead_request *req, 0, 0, dst_size); chcr_req->key_ctx.ctx_hdr = aeadctx->key_ctx_hdr; - if (op_type == CHCR_ENCRYPT_OP || + if (reqctx->op == CHCR_ENCRYPT_OP || subtype == CRYPTO_ALG_SUB_TYPE_CTR_SHA || subtype == CRYPTO_ALG_SUB_TYPE_CTR_NULL) memcpy(chcr_req->key_ctx.key, aeadctx->key, @@ -2376,20 +2370,18 @@ static struct sk_buff *create_authenc_wr(struct aead_request *req, } phys_cpl = (struct cpl_rx_phys_dsgl *)((u8 *)(chcr_req + 1) + kctx_len); ulptx = (struct ulptx_sgl *)((u8 *)(phys_cpl + 1) + dst_size); - chcr_add_aead_dst_ent(req, phys_cpl, assoclen, op_type, qid); - chcr_add_aead_src_ent(req, ulptx, assoclen, op_type); + chcr_add_aead_dst_ent(req, phys_cpl, assoclen, qid); + chcr_add_aead_src_ent(req, ulptx, assoclen); atomic_inc(&adap->chcr_stats.cipher_rqst); temp = sizeof(struct cpl_rx_phys_dsgl) + dst_size + kctx_len + (reqctx->imm ? (assoclen + IV + req->cryptlen) : 0); create_wreq(a_ctx(tfm), chcr_req, &req->base, reqctx->imm, size, transhdr_len, temp, 0); reqctx->skb = skb; - reqctx->op = op_type; return skb; err: - chcr_aead_dma_unmap(&ULD_CTX(a_ctx(tfm))->lldi.pdev->dev, req, - op_type); + chcr_aead_common_exit(req); return ERR_PTR(error); } @@ -2408,11 +2400,14 @@ int chcr_aead_dma_map(struct device *dev, -authsize : authsize); if (!req->cryptlen || !dst_size) return 0; - reqctx->iv_dma = dma_map_single(dev, reqctx->iv, IV, + reqctx->iv_dma = dma_map_single(dev, reqctx->iv, (IV + reqctx->b0_len), DMA_BIDIRECTIONAL); if (dma_mapping_error(dev, reqctx->iv_dma)) return -ENOMEM; - + if (reqctx->b0_len) + reqctx->b0_dma = reqctx->iv_dma + IV; + else + reqctx->b0_dma = 0; if (req->src == req->dst) { error = dma_map_sg(dev, req->src, sg_nents(req->src), DMA_BIDIRECTIONAL); @@ -2452,7 +2447,7 @@ void chcr_aead_dma_unmap(struct device *dev, if (!req->cryptlen || !dst_size) return; - dma_unmap_single(dev, reqctx->iv_dma, IV, + dma_unmap_single(dev, reqctx->iv_dma, (IV + reqctx->b0_len), DMA_BIDIRECTIONAL); if (req->src == req->dst) { dma_unmap_sg(dev, req->src, sg_nents(req->src), @@ -2467,8 +2462,7 @@ void chcr_aead_dma_unmap(struct device *dev, void chcr_add_aead_src_ent(struct aead_request *req, struct ulptx_sgl *ulptx, - unsigned int assoclen, - unsigned short op_type) + unsigned int assoclen) { struct ulptx_walk ulp_walk; struct chcr_aead_reqctx *reqctx = aead_request_ctx(req); @@ -2476,7 +2470,7 @@ void chcr_add_aead_src_ent(struct aead_request *req, if (reqctx->imm) { u8 *buf = (u8 *)ulptx; - if (reqctx->b0_dma) { + if (reqctx->b0_len) { memcpy(buf, reqctx->scratch_pad, reqctx->b0_len); buf += reqctx->b0_len; } @@ -2489,7 +2483,7 @@ void chcr_add_aead_src_ent(struct aead_request *req, buf, req->cryptlen, req->assoclen); } else { ulptx_walk_init(&ulp_walk, ulptx); - if (reqctx->b0_dma) + if (reqctx->b0_len) ulptx_walk_add_page(&ulp_walk, reqctx->b0_len, &reqctx->b0_dma); ulptx_walk_add_sg(&ulp_walk, req->src, assoclen, 0); @@ -2503,7 +2497,6 @@ void chcr_add_aead_src_ent(struct aead_request *req, void chcr_add_aead_dst_ent(struct aead_request *req, struct cpl_rx_phys_dsgl *phys_cpl, unsigned int assoclen, - unsigned short op_type, unsigned short qid) { struct chcr_aead_reqctx *reqctx = aead_request_ctx(req); @@ -2513,32 +2506,30 @@ void chcr_add_aead_dst_ent(struct aead_request *req, u32 temp; dsgl_walk_init(&dsgl_walk, phys_cpl); - if (reqctx->b0_dma) + if (reqctx->b0_len) dsgl_walk_add_page(&dsgl_walk, reqctx->b0_len, &reqctx->b0_dma); dsgl_walk_add_sg(&dsgl_walk, req->dst, assoclen, 0); dsgl_walk_add_page(&dsgl_walk, IV, &reqctx->iv_dma); - temp = req->cryptlen + (op_type ? -authsize : authsize); + temp = req->cryptlen + (reqctx->op ? -authsize : authsize); dsgl_walk_add_sg(&dsgl_walk, req->dst, temp, req->assoclen); dsgl_walk_end(&dsgl_walk, qid); } void chcr_add_cipher_src_ent(struct ablkcipher_request *req, - struct ulptx_sgl *ulptx, + void *ulptx, struct cipher_wr_param *wrparam) { struct ulptx_walk ulp_walk; struct chcr_blkcipher_req_ctx *reqctx = ablkcipher_request_ctx(req); + u8 *buf = ulptx; + memcpy(buf, reqctx->iv, IV); + buf += IV; if (reqctx->imm) { - u8 *buf = (u8 *)ulptx; - - memcpy(buf, reqctx->iv, IV); - buf += IV; sg_pcopy_to_buffer(req->src, sg_nents(req->src), buf, wrparam->bytes, reqctx->processed); } else { - ulptx_walk_init(&ulp_walk, ulptx); - ulptx_walk_add_page(&ulp_walk, IV, &reqctx->iv_dma); + ulptx_walk_init(&ulp_walk, (struct ulptx_sgl *)buf); ulptx_walk_add_sg(&ulp_walk, reqctx->srcsg, wrparam->bytes, reqctx->src_ofst); reqctx->srcsg = ulp_walk.last_sg; @@ -2556,7 +2547,6 @@ void chcr_add_cipher_dst_ent(struct ablkcipher_request *req, struct dsgl_walk dsgl_walk; dsgl_walk_init(&dsgl_walk, phys_cpl); - dsgl_walk_add_page(&dsgl_walk, IV, &reqctx->iv_dma); dsgl_walk_add_sg(&dsgl_walk, reqctx->dstsg, wrparam->bytes, reqctx->dst_ofst); reqctx->dstsg = dsgl_walk.last_sg; @@ -2630,12 +2620,6 @@ int chcr_cipher_dma_map(struct device *dev, struct ablkcipher_request *req) { int error; - struct chcr_blkcipher_req_ctx *reqctx = ablkcipher_request_ctx(req); - - reqctx->iv_dma = dma_map_single(dev, reqctx->iv, IV, - DMA_BIDIRECTIONAL); - if (dma_mapping_error(dev, reqctx->iv_dma)) - return -ENOMEM; if (req->src == req->dst) { error = dma_map_sg(dev, req->src, sg_nents(req->src), @@ -2658,17 +2642,12 @@ int chcr_cipher_dma_map(struct device *dev, return 0; err: - dma_unmap_single(dev, reqctx->iv_dma, IV, DMA_BIDIRECTIONAL); return -ENOMEM; } void chcr_cipher_dma_unmap(struct device *dev, struct ablkcipher_request *req) { - struct chcr_blkcipher_req_ctx *reqctx = ablkcipher_request_ctx(req); - - dma_unmap_single(dev, reqctx->iv_dma, IV, - DMA_BIDIRECTIONAL); if (req->src == req->dst) { dma_unmap_sg(dev, req->src, sg_nents(req->src), DMA_BIDIRECTIONAL); @@ -2738,7 +2717,8 @@ static inline int crypto_ccm_check_iv(const u8 *iv) static int ccm_format_packet(struct aead_request *req, struct chcr_aead_ctx *aeadctx, unsigned int sub_type, - unsigned short op_type) + unsigned short op_type, + unsigned int assoclen) { struct chcr_aead_reqctx *reqctx = aead_request_ctx(req); int rc = 0; @@ -2748,13 +2728,13 @@ static int ccm_format_packet(struct aead_request *req, memcpy(reqctx->iv + 1, &aeadctx->salt[0], 3); memcpy(reqctx->iv + 4, req->iv, 8); memset(reqctx->iv + 12, 0, 4); - *((unsigned short *)(reqctx->scratch_pad + 16)) = - htons(req->assoclen - 8); } else { memcpy(reqctx->iv, req->iv, 16); - *((unsigned short *)(reqctx->scratch_pad + 16)) = - htons(req->assoclen); } + if (assoclen) + *((unsigned short *)(reqctx->scratch_pad + 16)) = + htons(assoclen); + generate_b0(req, aeadctx, op_type); /* zero the ctr value */ memset(reqctx->iv + 15 - reqctx->iv[0], 0, reqctx->iv[0] + 1); @@ -2836,8 +2816,7 @@ static int aead_ccm_validate_input(unsigned short op_type, static struct sk_buff *create_aead_ccm_wr(struct aead_request *req, unsigned short qid, - int size, - unsigned short op_type) + int size) { struct crypto_aead *tfm = crypto_aead_reqtfm(req); struct chcr_aead_ctx *aeadctx = AEAD_CTX(a_ctx(tfm)); @@ -2855,22 +2834,20 @@ static struct sk_buff *create_aead_ccm_wr(struct aead_request *req, GFP_ATOMIC; struct adapter *adap = padap(a_ctx(tfm)->dev); - reqctx->b0_dma = 0; sub_type = get_aead_subtype(tfm); if (sub_type == CRYPTO_ALG_SUB_TYPE_AEAD_RFC4309) assoclen -= 8; - error = chcr_aead_common_init(req, op_type); + reqctx->b0_len = CCM_B0_SIZE + (assoclen ? CCM_AAD_FIELD_SIZE : 0); + error = chcr_aead_common_init(req); if (error) return ERR_PTR(error); - - reqctx->b0_len = CCM_B0_SIZE + (assoclen ? CCM_AAD_FIELD_SIZE : 0); - error = aead_ccm_validate_input(op_type, req, aeadctx, sub_type); + error = aead_ccm_validate_input(reqctx->op, req, aeadctx, sub_type); if (error) goto err; dnents = sg_nents_xlen(req->dst, assoclen, CHCR_DST_SG_SIZE, 0); dnents += sg_nents_xlen(req->dst, req->cryptlen - + (op_type ? -authsize : authsize), + + (reqctx->op ? -authsize : authsize), CHCR_DST_SG_SIZE, req->assoclen); dnents += MIN_CCM_SG; // For IV and B0 dst_size = get_space_for_phys_dsgl(dnents); @@ -2886,11 +2863,10 @@ static struct sk_buff *create_aead_ccm_wr(struct aead_request *req, transhdr_len = roundup(transhdr_len, 16); if (chcr_aead_need_fallback(req, dnents, T6_MAX_AAD_SIZE - - reqctx->b0_len, transhdr_len, op_type)) { + reqctx->b0_len, transhdr_len, reqctx->op)) { atomic_inc(&adap->chcr_stats.fallback); - chcr_aead_dma_unmap(&ULD_CTX(a_ctx(tfm))->lldi.pdev->dev, req, - op_type); - return ERR_PTR(chcr_aead_fallback(req, op_type)); + chcr_aead_common_exit(req); + return ERR_PTR(chcr_aead_fallback(req, reqctx->op)); } skb = alloc_skb(SGE_MAX_WR_LEN, flags); @@ -2901,7 +2877,7 @@ static struct sk_buff *create_aead_ccm_wr(struct aead_request *req, chcr_req = (struct chcr_wr *) __skb_put_zero(skb, transhdr_len); - fill_sec_cpl_for_aead(&chcr_req->sec_cpl, dst_size, req, op_type); + fill_sec_cpl_for_aead(&chcr_req->sec_cpl, dst_size, req, reqctx->op); chcr_req->key_ctx.ctx_hdr = aeadctx->key_ctx_hdr; memcpy(chcr_req->key_ctx.key, aeadctx->key, aeadctx->enckey_len); @@ -2910,21 +2886,11 @@ static struct sk_buff *create_aead_ccm_wr(struct aead_request *req, phys_cpl = (struct cpl_rx_phys_dsgl *)((u8 *)(chcr_req + 1) + kctx_len); ulptx = (struct ulptx_sgl *)((u8 *)(phys_cpl + 1) + dst_size); - error = ccm_format_packet(req, aeadctx, sub_type, op_type); + error = ccm_format_packet(req, aeadctx, sub_type, reqctx->op, assoclen); if (error) goto dstmap_fail; - - reqctx->b0_dma = dma_map_single(&ULD_CTX(a_ctx(tfm))->lldi.pdev->dev, - &reqctx->scratch_pad, reqctx->b0_len, - DMA_BIDIRECTIONAL); - if (dma_mapping_error(&ULD_CTX(a_ctx(tfm))->lldi.pdev->dev, - reqctx->b0_dma)) { - error = -ENOMEM; - goto dstmap_fail; - } - - chcr_add_aead_dst_ent(req, phys_cpl, assoclen, op_type, qid); - chcr_add_aead_src_ent(req, ulptx, assoclen, op_type); + chcr_add_aead_dst_ent(req, phys_cpl, assoclen, qid); + chcr_add_aead_src_ent(req, ulptx, assoclen); atomic_inc(&adap->chcr_stats.aead_rqst); temp = sizeof(struct cpl_rx_phys_dsgl) + dst_size + @@ -2933,20 +2899,18 @@ static struct sk_buff *create_aead_ccm_wr(struct aead_request *req, create_wreq(a_ctx(tfm), chcr_req, &req->base, reqctx->imm, 0, transhdr_len, temp, 0); reqctx->skb = skb; - reqctx->op = op_type; return skb; dstmap_fail: kfree_skb(skb); err: - chcr_aead_dma_unmap(&ULD_CTX(a_ctx(tfm))->lldi.pdev->dev, req, op_type); + chcr_aead_common_exit(req); return ERR_PTR(error); } static struct sk_buff *create_gcm_wr(struct aead_request *req, unsigned short qid, - int size, - unsigned short op_type) + int size) { struct crypto_aead *tfm = crypto_aead_reqtfm(req); struct chcr_aead_ctx *aeadctx = AEAD_CTX(a_ctx(tfm)); @@ -2966,13 +2930,13 @@ static struct sk_buff *create_gcm_wr(struct aead_request *req, if (get_aead_subtype(tfm) == CRYPTO_ALG_SUB_TYPE_AEAD_RFC4106) assoclen = req->assoclen - 8; - reqctx->b0_dma = 0; - error = chcr_aead_common_init(req, op_type); + reqctx->b0_len = 0; + error = chcr_aead_common_init(req); if (error) return ERR_PTR(error); dnents = sg_nents_xlen(req->dst, assoclen, CHCR_DST_SG_SIZE, 0); dnents += sg_nents_xlen(req->dst, req->cryptlen + - (op_type ? -authsize : authsize), + (reqctx->op ? -authsize : authsize), CHCR_DST_SG_SIZE, req->assoclen); dnents += MIN_GCM_SG; // For IV dst_size = get_space_for_phys_dsgl(dnents); @@ -2986,11 +2950,11 @@ static struct sk_buff *create_gcm_wr(struct aead_request *req, transhdr_len += temp; transhdr_len = roundup(transhdr_len, 16); if (chcr_aead_need_fallback(req, dnents, T6_MAX_AAD_SIZE, - transhdr_len, op_type)) { + transhdr_len, reqctx->op)) { + atomic_inc(&adap->chcr_stats.fallback); - chcr_aead_dma_unmap(&ULD_CTX(a_ctx(tfm))->lldi.pdev->dev, req, - op_type); - return ERR_PTR(chcr_aead_fallback(req, op_type)); + chcr_aead_common_exit(req); + return ERR_PTR(chcr_aead_fallback(req, reqctx->op)); } skb = alloc_skb(SGE_MAX_WR_LEN, flags); if (!skb) { @@ -3001,7 +2965,7 @@ static struct sk_buff *create_gcm_wr(struct aead_request *req, chcr_req = __skb_put_zero(skb, transhdr_len); //Offset of tag from end - temp = (op_type == CHCR_ENCRYPT_OP) ? 0 : authsize; + temp = (reqctx->op == CHCR_ENCRYPT_OP) ? 0 : authsize; chcr_req->sec_cpl.op_ivinsrtofst = FILL_SEC_CPL_OP_IVINSR( a_ctx(tfm)->dev->rx_channel_id, 2, (assoclen + 1)); @@ -3014,7 +2978,7 @@ static struct sk_buff *create_gcm_wr(struct aead_request *req, FILL_SEC_CPL_AUTHINSERT(0, assoclen + IV + 1, temp, temp); chcr_req->sec_cpl.seqno_numivs = - FILL_SEC_CPL_SCMD0_SEQNO(op_type, (op_type == + FILL_SEC_CPL_SCMD0_SEQNO(reqctx->op, (reqctx->op == CHCR_ENCRYPT_OP) ? 1 : 0, CHCR_SCMD_CIPHER_MODE_AES_GCM, CHCR_SCMD_AUTH_MODE_GHASH, @@ -3040,19 +3004,18 @@ static struct sk_buff *create_gcm_wr(struct aead_request *req, phys_cpl = (struct cpl_rx_phys_dsgl *)((u8 *)(chcr_req + 1) + kctx_len); ulptx = (struct ulptx_sgl *)((u8 *)(phys_cpl + 1) + dst_size); - chcr_add_aead_dst_ent(req, phys_cpl, assoclen, op_type, qid); - chcr_add_aead_src_ent(req, ulptx, assoclen, op_type); + chcr_add_aead_dst_ent(req, phys_cpl, assoclen, qid); + chcr_add_aead_src_ent(req, ulptx, assoclen); atomic_inc(&adap->chcr_stats.aead_rqst); temp = sizeof(struct cpl_rx_phys_dsgl) + dst_size + kctx_len + (reqctx->imm ? (assoclen + IV + req->cryptlen) : 0); create_wreq(a_ctx(tfm), chcr_req, &req->base, reqctx->imm, size, transhdr_len, temp, reqctx->verify); reqctx->skb = skb; - reqctx->op = op_type; return skb; err: - chcr_aead_dma_unmap(&ULD_CTX(a_ctx(tfm))->lldi.pdev->dev, req, op_type); + chcr_aead_common_exit(req); return ERR_PTR(error); } @@ -3461,6 +3424,7 @@ static int chcr_authenc_setkey(struct crypto_aead *authenc, const u8 *key, } { SHASH_DESC_ON_STACK(shash, base_hash); + shash->tfm = base_hash; shash->flags = crypto_shash_get_flags(base_hash); bs = crypto_shash_blocksize(base_hash); @@ -3585,13 +3549,13 @@ out: } static int chcr_aead_op(struct aead_request *req, - unsigned short op_type, int size, create_wr_t create_wr_fn) { struct crypto_aead *tfm = crypto_aead_reqtfm(req); struct uld_ctx *u_ctx; struct sk_buff *skb; + int isfull = 0; if (!a_ctx(tfm)->dev) { pr_err("chcr : %s : No crypto device.\n", __func__); @@ -3600,13 +3564,13 @@ static int chcr_aead_op(struct aead_request *req, u_ctx = ULD_CTX(a_ctx(tfm)); if (cxgb4_is_crypto_q_full(u_ctx->lldi.ports[0], a_ctx(tfm)->tx_qidx)) { + isfull = 1; if (!(req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) - return -EBUSY; + return -ENOSPC; } /* Form a WR from req */ - skb = create_wr_fn(req, u_ctx->lldi.rxq_ids[a_ctx(tfm)->rx_qidx], size, - op_type); + skb = create_wr_fn(req, u_ctx->lldi.rxq_ids[a_ctx(tfm)->rx_qidx], size); if (IS_ERR(skb) || !skb) return PTR_ERR(skb); @@ -3614,7 +3578,7 @@ static int chcr_aead_op(struct aead_request *req, skb->dev = u_ctx->lldi.ports[0]; set_wr_txq(skb, CPL_PRIORITY_DATA, a_ctx(tfm)->tx_qidx); chcr_send_wr(skb); - return -EINPROGRESS; + return isfull ? -EBUSY : -EINPROGRESS; } static int chcr_aead_encrypt(struct aead_request *req) @@ -3623,21 +3587,19 @@ static int chcr_aead_encrypt(struct aead_request *req) struct chcr_aead_reqctx *reqctx = aead_request_ctx(req); reqctx->verify = VERIFY_HW; + reqctx->op = CHCR_ENCRYPT_OP; switch (get_aead_subtype(tfm)) { case CRYPTO_ALG_SUB_TYPE_CTR_SHA: case CRYPTO_ALG_SUB_TYPE_CBC_SHA: case CRYPTO_ALG_SUB_TYPE_CBC_NULL: case CRYPTO_ALG_SUB_TYPE_CTR_NULL: - return chcr_aead_op(req, CHCR_ENCRYPT_OP, 0, - create_authenc_wr); + return chcr_aead_op(req, 0, create_authenc_wr); case CRYPTO_ALG_SUB_TYPE_AEAD_CCM: case CRYPTO_ALG_SUB_TYPE_AEAD_RFC4309: - return chcr_aead_op(req, CHCR_ENCRYPT_OP, 0, - create_aead_ccm_wr); + return chcr_aead_op(req, 0, create_aead_ccm_wr); default: - return chcr_aead_op(req, CHCR_ENCRYPT_OP, 0, - create_gcm_wr); + return chcr_aead_op(req, 0, create_gcm_wr); } } @@ -3655,21 +3617,18 @@ static int chcr_aead_decrypt(struct aead_request *req) size = 0; reqctx->verify = VERIFY_HW; } - + reqctx->op = CHCR_DECRYPT_OP; switch (get_aead_subtype(tfm)) { case CRYPTO_ALG_SUB_TYPE_CBC_SHA: case CRYPTO_ALG_SUB_TYPE_CTR_SHA: case CRYPTO_ALG_SUB_TYPE_CBC_NULL: case CRYPTO_ALG_SUB_TYPE_CTR_NULL: - return chcr_aead_op(req, CHCR_DECRYPT_OP, size, - create_authenc_wr); + return chcr_aead_op(req, size, create_authenc_wr); case CRYPTO_ALG_SUB_TYPE_AEAD_CCM: case CRYPTO_ALG_SUB_TYPE_AEAD_RFC4309: - return chcr_aead_op(req, CHCR_DECRYPT_OP, size, - create_aead_ccm_wr); + return chcr_aead_op(req, size, create_aead_ccm_wr); default: - return chcr_aead_op(req, CHCR_DECRYPT_OP, size, - create_gcm_wr); + return chcr_aead_op(req, size, create_gcm_wr); } } diff --git a/drivers/crypto/chelsio/chcr_algo.h b/drivers/crypto/chelsio/chcr_algo.h index dba3dff1e209..1871500309e2 100644 --- a/drivers/crypto/chelsio/chcr_algo.h +++ b/drivers/crypto/chelsio/chcr_algo.h @@ -146,7 +146,7 @@ kctx_len) #define CIPHER_TRANSHDR_SIZE(kctx_len, sge_pairs) \ (TRANSHDR_SIZE((kctx_len)) + (sge_pairs) +\ - sizeof(struct cpl_rx_phys_dsgl)) + sizeof(struct cpl_rx_phys_dsgl) + AES_BLOCK_SIZE) #define HASH_TRANSHDR_SIZE(kctx_len)\ (TRANSHDR_SIZE(kctx_len) + DUMMY_BYTES) @@ -259,7 +259,6 @@ ULP_TX_SC_MORE_V((immdatalen))) #define MAX_NK 8 #define MAX_DSGL_ENT 32 -#define MIN_CIPHER_SG 1 /* IV */ #define MIN_AUTH_SG 1 /* IV */ #define MIN_GCM_SG 1 /* IV */ #define MIN_DIGEST_SG 1 /*Partial Buffer*/ diff --git a/drivers/crypto/chelsio/chcr_core.h b/drivers/crypto/chelsio/chcr_core.h index 1a20424e18c6..de3a9c085daf 100644 --- a/drivers/crypto/chelsio/chcr_core.h +++ b/drivers/crypto/chelsio/chcr_core.h @@ -56,7 +56,7 @@ #define MAX_SALT 4 #define CIP_WR_MIN_LEN (sizeof(struct chcr_wr) + \ sizeof(struct cpl_rx_phys_dsgl) + \ - sizeof(struct ulptx_sgl)) + sizeof(struct ulptx_sgl) + 16) //IV #define HASH_WR_MIN_LEN (sizeof(struct chcr_wr) + \ DUMMY_BYTES + \ diff --git a/drivers/crypto/chelsio/chcr_crypto.h b/drivers/crypto/chelsio/chcr_crypto.h index c8e8972af283..54835cb109e5 100644 --- a/drivers/crypto/chelsio/chcr_crypto.h +++ b/drivers/crypto/chelsio/chcr_crypto.h @@ -190,8 +190,8 @@ struct chcr_aead_reqctx { short int dst_nents; u16 imm; u16 verify; - u8 iv[CHCR_MAX_CRYPTO_IV_LEN]; - unsigned char scratch_pad[MAX_SCRATCH_PAD_SIZE]; + u8 iv[CHCR_MAX_CRYPTO_IV_LEN + MAX_SCRATCH_PAD_SIZE]; + u8 *scratch_pad; }; struct ulptx_walk { @@ -295,7 +295,6 @@ struct chcr_blkcipher_req_ctx { unsigned int src_ofst; unsigned int dst_ofst; unsigned int op; - dma_addr_t iv_dma; u16 imm; u8 iv[CHCR_MAX_CRYPTO_IV_LEN]; }; @@ -312,8 +311,7 @@ struct chcr_alg_template { typedef struct sk_buff *(*create_wr_t)(struct aead_request *req, unsigned short qid, - int size, - unsigned short op_type); + int size); void chcr_verify_tag(struct aead_request *req, u8 *input, int *err); int chcr_aead_dma_map(struct device *dev, struct aead_request *req, @@ -322,12 +320,12 @@ void chcr_aead_dma_unmap(struct device *dev, struct aead_request *req, unsigned short op_type); void chcr_add_aead_dst_ent(struct aead_request *req, struct cpl_rx_phys_dsgl *phys_cpl, - unsigned int assoclen, unsigned short op_type, + unsigned int assoclen, unsigned short qid); void chcr_add_aead_src_ent(struct aead_request *req, struct ulptx_sgl *ulptx, - unsigned int assoclen, unsigned short op_type); + unsigned int assoclen); void chcr_add_cipher_src_ent(struct ablkcipher_request *req, - struct ulptx_sgl *ulptx, + void *ulptx, struct cipher_wr_param *wrparam); int chcr_cipher_dma_map(struct device *dev, struct ablkcipher_request *req); void chcr_cipher_dma_unmap(struct device *dev, struct ablkcipher_request *req); @@ -340,4 +338,5 @@ void chcr_add_hash_src_ent(struct ahash_request *req, struct ulptx_sgl *ulptx, struct hash_wr_param *param); int chcr_hash_dma_map(struct device *dev, struct ahash_request *req); void chcr_hash_dma_unmap(struct device *dev, struct ahash_request *req); +void chcr_aead_common_exit(struct aead_request *req); #endif /* __CHCR_CRYPTO_H__ */ diff --git a/drivers/crypto/chelsio/chcr_ipsec.c b/drivers/crypto/chelsio/chcr_ipsec.c index 8e0aa3f175c9..461b97e2f1fd 100644 --- a/drivers/crypto/chelsio/chcr_ipsec.c +++ b/drivers/crypto/chelsio/chcr_ipsec.c @@ -346,18 +346,23 @@ inline void *copy_cpltx_pktxt(struct sk_buff *skb, struct net_device *dev, void *pos) { + struct cpl_tx_pkt_core *cpl; + struct sge_eth_txq *q; struct adapter *adap; struct port_info *pi; - struct sge_eth_txq *q; - struct cpl_tx_pkt_core *cpl; - u64 cntrl = 0; u32 ctrl0, qidx; + u64 cntrl = 0; + int left; pi = netdev_priv(dev); adap = pi->adapter; qidx = skb->queue_mapping; q = &adap->sge.ethtxq[qidx + pi->first_qset]; + left = (void *)q->q.stat - pos; + if (!left) + pos = q->q.desc; + cpl = (struct cpl_tx_pkt_core *)pos; cntrl = TXPKT_L4CSUM_DIS_F | TXPKT_IPCSUM_DIS_F; @@ -382,18 +387,17 @@ inline void *copy_key_cpltx_pktxt(struct sk_buff *skb, void *pos, struct ipsec_sa_entry *sa_entry) { - struct adapter *adap; - struct port_info *pi; - struct sge_eth_txq *q; - unsigned int len, qidx; struct _key_ctx *key_ctx; int left, eoq, key_len; + struct sge_eth_txq *q; + struct adapter *adap; + struct port_info *pi; + unsigned int qidx; pi = netdev_priv(dev); adap = pi->adapter; qidx = skb->queue_mapping; q = &adap->sge.ethtxq[qidx + pi->first_qset]; - len = sa_entry->enckey_len + sizeof(struct cpl_tx_pkt_core); key_len = sa_entry->kctx_len; /* end of queue, reset pos to start of queue */ @@ -411,19 +415,14 @@ inline void *copy_key_cpltx_pktxt(struct sk_buff *skb, pos += sizeof(struct _key_ctx); left -= sizeof(struct _key_ctx); - if (likely(len <= left)) { + if (likely(key_len <= left)) { memcpy(key_ctx->key, sa_entry->key, key_len); pos += key_len; } else { - if (key_len <= left) { - memcpy(pos, sa_entry->key, key_len); - pos += key_len; - } else { - memcpy(pos, sa_entry->key, left); - memcpy(q->q.desc, sa_entry->key + left, - key_len - left); - pos = (u8 *)q->q.desc + (key_len - left); - } + memcpy(pos, sa_entry->key, left); + memcpy(q->q.desc, sa_entry->key + left, + key_len - left); + pos = (u8 *)q->q.desc + (key_len - left); } /* Copy CPL TX PKT XT */ pos = copy_cpltx_pktxt(skb, dev, pos); diff --git a/drivers/crypto/chelsio/chtls/chtls.h b/drivers/crypto/chelsio/chtls/chtls.h index f4b8f1ec0061..a53a0e6ba024 100644 --- a/drivers/crypto/chelsio/chtls/chtls.h +++ b/drivers/crypto/chelsio/chtls/chtls.h @@ -67,11 +67,6 @@ enum { CPL_RET_UNKNOWN_TID = 4 /* unexpected unknown TID */ }; -#define TLS_RCV_ST_READ_HEADER 0xF0 -#define TLS_RCV_ST_READ_BODY 0xF1 -#define TLS_RCV_ST_READ_DONE 0xF2 -#define TLS_RCV_ST_READ_NB 0xF3 - #define LISTEN_INFO_HASH_SIZE 32 #define RSPQ_HASH_BITS 5 struct listen_info { @@ -149,6 +144,7 @@ struct chtls_dev { struct list_head rcu_node; struct list_head na_node; unsigned int send_page_order; + int max_host_sndbuf; struct key_map kmap; }; @@ -278,6 +274,7 @@ struct tlsrx_cmp_hdr { #define TLSRX_HDR_PKT_MAC_ERROR_F TLSRX_HDR_PKT_MAC_ERROR_V(1U) #define TLSRX_HDR_PKT_ERROR_M 0x1F +#define CONTENT_TYPE_ERROR 0x7F struct ulp_mem_rw { __be32 cmd; @@ -347,8 +344,8 @@ enum { ULPCB_FLAG_HOLD = 1 << 3, /* skb not ready for Tx yet */ ULPCB_FLAG_COMPL = 1 << 4, /* request WR completion */ ULPCB_FLAG_URG = 1 << 5, /* urgent data */ - ULPCB_FLAG_TLS_ND = 1 << 6, /* payload of zero length */ - ULPCB_FLAG_NO_HDR = 1 << 7, /* not a ofld wr */ + ULPCB_FLAG_TLS_HDR = 1 << 6, /* payload with tls hdr */ + ULPCB_FLAG_NO_HDR = 1 << 7, /* not a ofld wr */ }; /* The ULP mode/submode of an skbuff */ diff --git a/drivers/crypto/chelsio/chtls/chtls_cm.c b/drivers/crypto/chelsio/chtls/chtls_cm.c index 82a473a0cefa..2bb6f0380758 100644 --- a/drivers/crypto/chelsio/chtls/chtls_cm.c +++ b/drivers/crypto/chelsio/chtls/chtls_cm.c @@ -1537,6 +1537,10 @@ static int chtls_rx_data(struct chtls_dev *cdev, struct sk_buff *skb) struct sock *sk; sk = lookup_tid(cdev->tids, hwtid); + if (unlikely(!sk)) { + pr_err("can't find conn. for hwtid %u.\n", hwtid); + return -EINVAL; + } skb_dst_set(skb, NULL); process_cpl_msg(chtls_recv_data, sk, skb); return 0; @@ -1585,6 +1589,10 @@ static int chtls_rx_pdu(struct chtls_dev *cdev, struct sk_buff *skb) struct sock *sk; sk = lookup_tid(cdev->tids, hwtid); + if (unlikely(!sk)) { + pr_err("can't find conn. for hwtid %u.\n", hwtid); + return -EINVAL; + } skb_dst_set(skb, NULL); process_cpl_msg(chtls_recv_pdu, sk, skb); return 0; @@ -1600,12 +1608,14 @@ static void chtls_set_hdrlen(struct sk_buff *skb, unsigned int nlen) static void chtls_rx_hdr(struct sock *sk, struct sk_buff *skb) { - struct cpl_rx_tls_cmp *cmp_cpl = cplhdr(skb); + struct tlsrx_cmp_hdr *tls_hdr_pkt; + struct cpl_rx_tls_cmp *cmp_cpl; struct sk_buff *skb_rec; struct chtls_sock *csk; struct chtls_hws *tlsk; struct tcp_sock *tp; + cmp_cpl = cplhdr(skb); csk = rcu_dereference_sk_user_data(sk); tlsk = &csk->tlshws; tp = tcp_sk(sk); @@ -1615,16 +1625,18 @@ static void chtls_rx_hdr(struct sock *sk, struct sk_buff *skb) skb_reset_transport_header(skb); __skb_pull(skb, sizeof(*cmp_cpl)); + tls_hdr_pkt = (struct tlsrx_cmp_hdr *)skb->data; + if (tls_hdr_pkt->res_to_mac_error & TLSRX_HDR_PKT_ERROR_M) + tls_hdr_pkt->type = CONTENT_TYPE_ERROR; if (!skb->data_len) - __skb_trim(skb, CPL_RX_TLS_CMP_LENGTH_G - (ntohl(cmp_cpl->pdulength_length))); + __skb_trim(skb, TLS_HEADER_LENGTH); tp->rcv_nxt += CPL_RX_TLS_CMP_PDULENGTH_G(ntohl(cmp_cpl->pdulength_length)); + ULP_SKB_CB(skb)->flags |= ULPCB_FLAG_TLS_HDR; skb_rec = __skb_dequeue(&tlsk->sk_recv_queue); if (!skb_rec) { - ULP_SKB_CB(skb)->flags |= ULPCB_FLAG_TLS_ND; __skb_queue_tail(&sk->sk_receive_queue, skb); } else { chtls_set_hdrlen(skb, tlsk->pldlen); @@ -1646,6 +1658,10 @@ static int chtls_rx_cmp(struct chtls_dev *cdev, struct sk_buff *skb) struct sock *sk; sk = lookup_tid(cdev->tids, hwtid); + if (unlikely(!sk)) { + pr_err("can't find conn. for hwtid %u.\n", hwtid); + return -EINVAL; + } skb_dst_set(skb, NULL); process_cpl_msg(chtls_rx_hdr, sk, skb); @@ -2105,6 +2121,10 @@ static int chtls_wr_ack(struct chtls_dev *cdev, struct sk_buff *skb) struct sock *sk; sk = lookup_tid(cdev->tids, hwtid); + if (unlikely(!sk)) { + pr_err("can't find conn. for hwtid %u.\n", hwtid); + return -EINVAL; + } process_cpl_msg(chtls_rx_ack, sk, skb); return 0; diff --git a/drivers/crypto/chelsio/chtls/chtls_hw.c b/drivers/crypto/chelsio/chtls/chtls_hw.c index 54a13aa99121..55d50140f9e5 100644 --- a/drivers/crypto/chelsio/chtls/chtls_hw.c +++ b/drivers/crypto/chelsio/chtls/chtls_hw.c @@ -213,7 +213,7 @@ static int chtls_key_info(struct chtls_sock *csk, struct _key_ctx *kctx, u32 keylen, u32 optname) { - unsigned char key[CHCR_KEYCTX_CIPHER_KEY_SIZE_256]; + unsigned char key[AES_KEYSIZE_128]; struct tls12_crypto_info_aes_gcm_128 *gcm_ctx; unsigned char ghash_h[AEAD_H_SIZE]; struct crypto_cipher *cipher; @@ -228,10 +228,6 @@ static int chtls_key_info(struct chtls_sock *csk, if (keylen == AES_KEYSIZE_128) { ck_size = CHCR_KEYCTX_CIPHER_KEY_SIZE_128; - } else if (keylen == AES_KEYSIZE_192) { - ck_size = CHCR_KEYCTX_CIPHER_KEY_SIZE_192; - } else if (keylen == AES_KEYSIZE_256) { - ck_size = CHCR_KEYCTX_CIPHER_KEY_SIZE_256; } else { pr_err("GCM: Invalid key length %d\n", keylen); return -EINVAL; diff --git a/drivers/crypto/chelsio/chtls/chtls_io.c b/drivers/crypto/chelsio/chtls/chtls_io.c index 5a75be43950f..51fc6821cbbf 100644 --- a/drivers/crypto/chelsio/chtls/chtls_io.c +++ b/drivers/crypto/chelsio/chtls/chtls_io.c @@ -907,11 +907,83 @@ static int chtls_skb_copy_to_page_nocache(struct sock *sk, } /* Read TLS header to find content type and data length */ -static u16 tls_header_read(struct tls_hdr *thdr, struct iov_iter *from) +static int tls_header_read(struct tls_hdr *thdr, struct iov_iter *from) { if (copy_from_iter(thdr, sizeof(*thdr), from) != sizeof(*thdr)) return -EFAULT; - return (__force u16)cpu_to_be16(thdr->length); + return (__force int)cpu_to_be16(thdr->length); +} + +static int csk_mem_free(struct chtls_dev *cdev, struct sock *sk) +{ + return (cdev->max_host_sndbuf - sk->sk_wmem_queued); +} + +static int csk_wait_memory(struct chtls_dev *cdev, + struct sock *sk, long *timeo_p) +{ + DEFINE_WAIT_FUNC(wait, woken_wake_function); + int sndbuf, err = 0; + long current_timeo; + long vm_wait = 0; + bool noblock; + + current_timeo = *timeo_p; + noblock = (*timeo_p ? false : true); + sndbuf = cdev->max_host_sndbuf; + if (csk_mem_free(cdev, sk)) { + current_timeo = (prandom_u32() % (HZ / 5)) + 2; + vm_wait = (prandom_u32() % (HZ / 5)) + 2; + } + + add_wait_queue(sk_sleep(sk), &wait); + while (1) { + sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk); + + if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN)) + goto do_error; + if (!*timeo_p) { + if (noblock) + set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); + goto do_nonblock; + } + if (signal_pending(current)) + goto do_interrupted; + sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk); + if (csk_mem_free(cdev, sk) && !vm_wait) + break; + + set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); + sk->sk_write_pending++; + sk_wait_event(sk, ¤t_timeo, sk->sk_err || + (sk->sk_shutdown & SEND_SHUTDOWN) || + (csk_mem_free(cdev, sk) && !vm_wait), &wait); + sk->sk_write_pending--; + + if (vm_wait) { + vm_wait -= current_timeo; + current_timeo = *timeo_p; + if (current_timeo != MAX_SCHEDULE_TIMEOUT) { + current_timeo -= vm_wait; + if (current_timeo < 0) + current_timeo = 0; + } + vm_wait = 0; + } + *timeo_p = current_timeo; + } +do_rm_wq: + remove_wait_queue(sk_sleep(sk), &wait); + return err; +do_error: + err = -EPIPE; + goto do_rm_wq; +do_nonblock: + err = -EAGAIN; + goto do_rm_wq; +do_interrupted: + err = sock_intr_errno(*timeo_p); + goto do_rm_wq; } int chtls_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) @@ -952,6 +1024,8 @@ int chtls_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) copy = mss - skb->len; skb->ip_summed = CHECKSUM_UNNECESSARY; } + if (!csk_mem_free(cdev, sk)) + goto wait_for_sndbuf; if (is_tls_tx(csk) && !csk->tlshws.txleft) { struct tls_hdr hdr; @@ -1009,9 +1083,10 @@ new_buf: int off = TCP_OFF(sk); bool merge; - if (page) - pg_size <<= compound_order(page); + if (!page) + goto wait_for_memory; + pg_size <<= compound_order(page); if (off < pg_size && skb_can_coalesce(skb, i, page, off)) { merge = 1; @@ -1099,8 +1174,10 @@ copy: if (ULP_SKB_CB(skb)->flags & ULPCB_FLAG_NO_APPEND) push_frames_if_head(sk); continue; +wait_for_sndbuf: + set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); wait_for_memory: - err = sk_stream_wait_memory(sk, &timeo); + err = csk_wait_memory(cdev, sk, &timeo); if (err) goto do_error; } @@ -1131,6 +1208,7 @@ int chtls_sendpage(struct sock *sk, struct page *page, int offset, size_t size, int flags) { struct chtls_sock *csk; + struct chtls_dev *cdev; int mss, err, copied; struct tcp_sock *tp; long timeo; @@ -1138,6 +1216,7 @@ int chtls_sendpage(struct sock *sk, struct page *page, tp = tcp_sk(sk); copied = 0; csk = rcu_dereference_sk_user_data(sk); + cdev = csk->cdev; timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT); err = sk_stream_wait_connect(sk, &timeo); @@ -1152,10 +1231,11 @@ int chtls_sendpage(struct sock *sk, struct page *page, struct sk_buff *skb = skb_peek_tail(&csk->txq); int copy, i; - copy = mss - skb->len; if (!skb || (ULP_SKB_CB(skb)->flags & ULPCB_FLAG_NO_APPEND) || - copy <= 0) { + (copy = mss - skb->len) <= 0) { new_buf: + if (!csk_mem_free(cdev, sk)) + goto wait_for_sndbuf; if (is_tls_tx(csk)) { skb = get_record_skb(sk, @@ -1167,7 +1247,7 @@ new_buf: skb = get_tx_skb(sk, 0); } if (!skb) - goto do_error; + goto wait_for_memory; copy = mss; } if (copy > size) @@ -1206,8 +1286,12 @@ new_buf: if (unlikely(ULP_SKB_CB(skb)->flags & ULPCB_FLAG_NO_APPEND)) push_frames_if_head(sk); continue; - +wait_for_sndbuf: set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); +wait_for_memory: + err = csk_wait_memory(cdev, sk, &timeo); + if (err) + goto do_error; } out: csk_reset_flag(csk, CSK_TX_MORE_DATA); @@ -1409,7 +1493,7 @@ static int chtls_pt_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, break; chtls_cleanup_rbuf(sk, copied); sk_wait_data(sk, &timeo, NULL); - continue; + continue; found_ok_skb: if (!skb->len) { skb_dst_set(skb, NULL); @@ -1449,31 +1533,13 @@ found_ok_skb: } } } - if (hws->rstate == TLS_RCV_ST_READ_BODY) { - if (skb_copy_datagram_msg(skb, offset, - msg, avail)) { - if (!copied) { - copied = -EFAULT; - break; - } - } - } else { - struct tlsrx_cmp_hdr *tls_hdr_pkt = - (struct tlsrx_cmp_hdr *)skb->data; - - if ((tls_hdr_pkt->res_to_mac_error & - TLSRX_HDR_PKT_ERROR_M)) - tls_hdr_pkt->type = 0x7F; - - /* CMP pld len is for recv seq */ - hws->rcvpld = skb->hdr_len; - if (skb_copy_datagram_msg(skb, offset, msg, avail)) { - if (!copied) { - copied = -EFAULT; - break; - } + if (skb_copy_datagram_msg(skb, offset, msg, avail)) { + if (!copied) { + copied = -EFAULT; + break; } } + copied += avail; len -= avail; hws->copied_seq += avail; @@ -1481,32 +1547,20 @@ skip_copy: if (tp->urg_data && after(tp->copied_seq, tp->urg_seq)) tp->urg_data = 0; - if (hws->rstate == TLS_RCV_ST_READ_BODY && - (avail + offset) >= skb->len) { + if ((avail + offset) >= skb->len) { if (likely(skb)) chtls_free_skb(sk, skb); buffers_freed++; - hws->rstate = TLS_RCV_ST_READ_HEADER; - atomic_inc(&adap->chcr_stats.tls_pdu_rx); - tp->copied_seq += hws->rcvpld; + if (ULP_SKB_CB(skb)->flags & ULPCB_FLAG_TLS_HDR) { + tp->copied_seq += skb->len; + hws->rcvpld = skb->hdr_len; + } else { + tp->copied_seq += hws->rcvpld; + } hws->copied_seq = 0; if (copied >= target && !skb_peek(&sk->sk_receive_queue)) break; - } else { - if (likely(skb)) { - if (ULP_SKB_CB(skb)->flags & - ULPCB_FLAG_TLS_ND) - hws->rstate = - TLS_RCV_ST_READ_HEADER; - else - hws->rstate = - TLS_RCV_ST_READ_BODY; - chtls_free_skb(sk, skb); - } - buffers_freed++; - tp->copied_seq += avail; - hws->copied_seq = 0; } } while (len > 0); diff --git a/drivers/crypto/chelsio/chtls/chtls_main.c b/drivers/crypto/chelsio/chtls/chtls_main.c index 007c45c38fc7..9b07f9165658 100644 --- a/drivers/crypto/chelsio/chtls/chtls_main.c +++ b/drivers/crypto/chelsio/chtls/chtls_main.c @@ -216,7 +216,6 @@ static void *chtls_uld_add(const struct cxgb4_lld_info *info) cdev->lldi = lldi; cdev->pdev = lldi->pdev; cdev->tids = lldi->tids; - cdev->ports = (struct net_device **)(cdev + 1); cdev->ports = lldi->ports; cdev->mtus = lldi->mtus; cdev->tids = lldi->tids; @@ -239,6 +238,7 @@ static void *chtls_uld_add(const struct cxgb4_lld_info *info) spin_lock_init(&cdev->idr_lock); cdev->send_page_order = min_t(uint, get_order(32768), send_page_order); + cdev->max_host_sndbuf = 48 * 1024; if (lldi->vr->key.size) if (chtls_init_kmap(cdev, lldi)) @@ -250,7 +250,7 @@ static void *chtls_uld_add(const struct cxgb4_lld_info *info) return cdev; out_rspq_skb: - for (j = 0; j <= i; j++) + for (j = 0; j < i; j++) kfree_skb(cdev->rspq_skb_cache[j]); kfree_skb(cdev->askb); out_skb: @@ -441,7 +441,7 @@ nomem: static int do_chtls_getsockopt(struct sock *sk, char __user *optval, int __user *optlen) { - struct tls_crypto_info crypto_info; + struct tls_crypto_info crypto_info = { 0 }; crypto_info.version = TLS_1_2_VERSION; if (copy_to_user(optval, &crypto_info, sizeof(struct tls_crypto_info))) @@ -491,9 +491,13 @@ static int do_chtls_setsockopt(struct sock *sk, int optname, switch (tmp_crypto_info.cipher_type) { case TLS_CIPHER_AES_GCM_128: { - rc = copy_from_user(crypto_info, optval, - sizeof(struct - tls12_crypto_info_aes_gcm_128)); + /* Obtain version and type from previous copy */ + crypto_info[0] = tmp_crypto_info; + /* Now copy the following data */ + rc = copy_from_user((char *)crypto_info + sizeof(*crypto_info), + optval + sizeof(*crypto_info), + sizeof(struct tls12_crypto_info_aes_gcm_128) + - sizeof(*crypto_info)); if (rc) { rc = -EFAULT; diff --git a/drivers/crypto/exynos-rng.c b/drivers/crypto/exynos-rng.c index 86f5f459762e..2cfabb99cb6e 100644 --- a/drivers/crypto/exynos-rng.c +++ b/drivers/crypto/exynos-rng.c @@ -319,8 +319,7 @@ static int exynos_rng_remove(struct platform_device *pdev) static int __maybe_unused exynos_rng_suspend(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct exynos_rng_dev *rng = platform_get_drvdata(pdev); + struct exynos_rng_dev *rng = dev_get_drvdata(dev); int ret; /* If we were never seeded then after resume it will be the same */ @@ -350,8 +349,7 @@ static int __maybe_unused exynos_rng_suspend(struct device *dev) static int __maybe_unused exynos_rng_resume(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct exynos_rng_dev *rng = platform_get_drvdata(pdev); + struct exynos_rng_dev *rng = dev_get_drvdata(dev); int ret; /* Never seeded so nothing to do */ diff --git a/drivers/crypto/inside-secure/safexcel.c b/drivers/crypto/inside-secure/safexcel.c index d4a81be0d7d2..4e86f864a952 100644 --- a/drivers/crypto/inside-secure/safexcel.c +++ b/drivers/crypto/inside-secure/safexcel.c @@ -20,6 +20,7 @@ #include <linux/platform_device.h> #include <linux/workqueue.h> +#include <crypto/internal/aead.h> #include <crypto/internal/hash.h> #include <crypto/internal/skcipher.h> @@ -152,8 +153,8 @@ static int eip197_load_firmwares(struct safexcel_crypto_priv *priv) EIP197_PE_ICE_SCRATCH_CTRL_CHANGE_ACCESS; writel(val, EIP197_PE(priv) + EIP197_PE_ICE_SCRATCH_CTRL); - memset(EIP197_PE(priv) + EIP197_PE_ICE_SCRATCH_RAM, 0, - EIP197_NUM_OF_SCRATCH_BLOCKS * sizeof(u32)); + memset_io(EIP197_PE(priv) + EIP197_PE_ICE_SCRATCH_RAM, 0, + EIP197_NUM_OF_SCRATCH_BLOCKS * sizeof(u32)); eip197_write_firmware(priv, fw[FW_IFPP], EIP197_PE_ICE_FPP_CTRL, EIP197_PE_ICE_RAM_CTRL_FPP_PROG_EN); @@ -352,6 +353,7 @@ static int safexcel_hw_init(struct safexcel_crypto_priv *priv) /* H/W capabilities selection */ val = EIP197_FUNCTION_RSVD; val |= EIP197_PROTOCOL_ENCRYPT_ONLY | EIP197_PROTOCOL_HASH_ONLY; + val |= EIP197_PROTOCOL_ENCRYPT_HASH | EIP197_PROTOCOL_HASH_DECRYPT; val |= EIP197_ALG_AES_ECB | EIP197_ALG_AES_CBC; val |= EIP197_ALG_SHA1 | EIP197_ALG_HMAC_SHA1; val |= EIP197_ALG_SHA2 | EIP197_ALG_HMAC_SHA2; @@ -537,6 +539,27 @@ finalize: EIP197_HIA_CDR(priv, ring) + EIP197_HIA_xDR_PREP_COUNT); } +inline int safexcel_rdesc_check_errors(struct safexcel_crypto_priv *priv, + struct safexcel_result_desc *rdesc) +{ + if (likely(!rdesc->result_data.error_code)) + return 0; + + if (rdesc->result_data.error_code & 0x407f) { + /* Fatal error (bits 0-7, 14) */ + dev_err(priv->dev, + "cipher: result: result descriptor error (%d)\n", + rdesc->result_data.error_code); + return -EIO; + } else if (rdesc->result_data.error_code == BIT(9)) { + /* Authentication failed */ + return -EBADMSG; + } + + /* All other non-fatal errors */ + return -EINVAL; +} + void safexcel_complete(struct safexcel_crypto_priv *priv, int ring) { struct safexcel_command_desc *cdesc; @@ -770,6 +793,9 @@ static struct safexcel_alg_template *safexcel_algs[] = { &safexcel_alg_hmac_sha1, &safexcel_alg_hmac_sha224, &safexcel_alg_hmac_sha256, + &safexcel_alg_authenc_hmac_sha1_cbc_aes, + &safexcel_alg_authenc_hmac_sha224_cbc_aes, + &safexcel_alg_authenc_hmac_sha256_cbc_aes, }; static int safexcel_register_algorithms(struct safexcel_crypto_priv *priv) @@ -781,6 +807,8 @@ static int safexcel_register_algorithms(struct safexcel_crypto_priv *priv) if (safexcel_algs[i]->type == SAFEXCEL_ALG_TYPE_SKCIPHER) ret = crypto_register_skcipher(&safexcel_algs[i]->alg.skcipher); + else if (safexcel_algs[i]->type == SAFEXCEL_ALG_TYPE_AEAD) + ret = crypto_register_aead(&safexcel_algs[i]->alg.aead); else ret = crypto_register_ahash(&safexcel_algs[i]->alg.ahash); @@ -794,6 +822,8 @@ fail: for (j = 0; j < i; j++) { if (safexcel_algs[j]->type == SAFEXCEL_ALG_TYPE_SKCIPHER) crypto_unregister_skcipher(&safexcel_algs[j]->alg.skcipher); + else if (safexcel_algs[j]->type == SAFEXCEL_ALG_TYPE_AEAD) + crypto_unregister_aead(&safexcel_algs[j]->alg.aead); else crypto_unregister_ahash(&safexcel_algs[j]->alg.ahash); } @@ -808,6 +838,8 @@ static void safexcel_unregister_algorithms(struct safexcel_crypto_priv *priv) for (i = 0; i < ARRAY_SIZE(safexcel_algs); i++) { if (safexcel_algs[i]->type == SAFEXCEL_ALG_TYPE_SKCIPHER) crypto_unregister_skcipher(&safexcel_algs[i]->alg.skcipher); + else if (safexcel_algs[i]->type == SAFEXCEL_ALG_TYPE_AEAD) + crypto_unregister_aead(&safexcel_algs[i]->alg.aead); else crypto_unregister_ahash(&safexcel_algs[i]->alg.ahash); } diff --git a/drivers/crypto/inside-secure/safexcel.h b/drivers/crypto/inside-secure/safexcel.h index b470a849721f..8b3ee9b59f53 100644 --- a/drivers/crypto/inside-secure/safexcel.h +++ b/drivers/crypto/inside-secure/safexcel.h @@ -11,8 +11,10 @@ #ifndef __SAFEXCEL_H__ #define __SAFEXCEL_H__ +#include <crypto/aead.h> #include <crypto/algapi.h> #include <crypto/internal/hash.h> +#include <crypto/sha.h> #include <crypto/skcipher.h> #define EIP197_HIA_VERSION_LE 0xca35 @@ -20,7 +22,7 @@ /* Static configuration */ #define EIP197_DEFAULT_RING_SIZE 400 -#define EIP197_MAX_TOKENS 5 +#define EIP197_MAX_TOKENS 8 #define EIP197_MAX_RINGS 4 #define EIP197_FETCH_COUNT 1 #define EIP197_MAX_BATCH_SZ 64 @@ -28,6 +30,17 @@ #define EIP197_GFP_FLAGS(base) ((base).flags & CRYPTO_TFM_REQ_MAY_SLEEP ? \ GFP_KERNEL : GFP_ATOMIC) +/* Custom on-stack requests (for invalidation) */ +#define EIP197_SKCIPHER_REQ_SIZE sizeof(struct skcipher_request) + \ + sizeof(struct safexcel_cipher_req) +#define EIP197_AHASH_REQ_SIZE sizeof(struct ahash_request) + \ + sizeof(struct safexcel_ahash_req) +#define EIP197_AEAD_REQ_SIZE sizeof(struct aead_request) + \ + sizeof(struct safexcel_cipher_req) +#define EIP197_REQUEST_ON_STACK(name, type, size) \ + char __##name##_desc[size] CRYPTO_MINALIGN_ATTR; \ + struct type##_request *name = (void *)__##name##_desc + /* Register base offsets */ #define EIP197_HIA_AIC(priv) ((priv)->base + (priv)->offsets.hia_aic) #define EIP197_HIA_AIC_G(priv) ((priv)->base + (priv)->offsets.hia_aic_g) @@ -274,7 +287,7 @@ struct safexcel_context_record { u32 control0; u32 control1; - __le32 data[12]; + __le32 data[24]; } __packed; /* control0 */ @@ -286,8 +299,8 @@ struct safexcel_context_record { #define CONTEXT_CONTROL_TYPE_CRYPTO_IN 0x5 #define CONTEXT_CONTROL_TYPE_ENCRYPT_HASH_OUT 0x6 #define CONTEXT_CONTROL_TYPE_DECRYPT_HASH_IN 0x7 -#define CONTEXT_CONTROL_TYPE_HASH_ENCRYPT_OUT 0x14 -#define CONTEXT_CONTROL_TYPE_HASH_DECRYPT_OUT 0x15 +#define CONTEXT_CONTROL_TYPE_HASH_ENCRYPT_OUT 0xe +#define CONTEXT_CONTROL_TYPE_HASH_DECRYPT_IN 0xf #define CONTEXT_CONTROL_RESTART_HASH BIT(4) #define CONTEXT_CONTROL_NO_FINISH_HASH BIT(5) #define CONTEXT_CONTROL_SIZE(n) ((n) << 8) @@ -391,11 +404,15 @@ struct safexcel_token { u8 opcode:4; } __packed; +#define EIP197_TOKEN_HASH_RESULT_VERIFY BIT(16) + #define EIP197_TOKEN_STAT_LAST_HASH BIT(0) #define EIP197_TOKEN_STAT_LAST_PACKET BIT(1) #define EIP197_TOKEN_OPCODE_DIRECTION 0x0 #define EIP197_TOKEN_OPCODE_INSERT 0x2 #define EIP197_TOKEN_OPCODE_NOOP EIP197_TOKEN_OPCODE_INSERT +#define EIP197_TOKEN_OPCODE_RETRIEVE 0x4 +#define EIP197_TOKEN_OPCODE_VERIFY 0xd #define EIP197_TOKEN_OPCODE_BYPASS GENMASK(3, 0) static inline void eip197_noop_token(struct safexcel_token *token) @@ -479,6 +496,7 @@ struct safexcel_ring { enum safexcel_alg_type { SAFEXCEL_ALG_TYPE_SKCIPHER, + SAFEXCEL_ALG_TYPE_AEAD, SAFEXCEL_ALG_TYPE_AHASH, }; @@ -581,6 +599,16 @@ struct safexcel_context { bool exit_inv; }; +struct safexcel_ahash_export_state { + u64 len; + u64 processed; + + u32 digest; + + u32 state[SHA256_DIGEST_SIZE / sizeof(u32)]; + u8 cache[SHA256_BLOCK_SIZE]; +}; + /* * Template structure to describe the algorithms in order to register them. * It also has the purpose to contain our private structure and is actually @@ -591,6 +619,7 @@ struct safexcel_alg_template { enum safexcel_alg_type type; union { struct skcipher_alg skcipher; + struct aead_alg aead; struct ahash_alg ahash; } alg; }; @@ -601,6 +630,8 @@ struct safexcel_inv_result { }; void safexcel_dequeue(struct safexcel_crypto_priv *priv, int ring); +int safexcel_rdesc_check_errors(struct safexcel_crypto_priv *priv, + struct safexcel_result_desc *rdesc); void safexcel_complete(struct safexcel_crypto_priv *priv, int ring); int safexcel_invalidate_cache(struct crypto_async_request *async, struct safexcel_crypto_priv *priv, @@ -625,6 +656,8 @@ struct safexcel_result_desc *safexcel_add_rdesc(struct safexcel_crypto_priv *pri bool first, bool last, dma_addr_t data, u32 len); void safexcel_inv_complete(struct crypto_async_request *req, int error); +int safexcel_hmac_setkey(const char *alg, const u8 *key, unsigned int keylen, + void *istate, void *ostate); /* available algorithms */ extern struct safexcel_alg_template safexcel_alg_ecb_aes; @@ -635,5 +668,8 @@ extern struct safexcel_alg_template safexcel_alg_sha256; extern struct safexcel_alg_template safexcel_alg_hmac_sha1; extern struct safexcel_alg_template safexcel_alg_hmac_sha224; extern struct safexcel_alg_template safexcel_alg_hmac_sha256; +extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sha1_cbc_aes; +extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sha224_cbc_aes; +extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sha256_cbc_aes; #endif diff --git a/drivers/crypto/inside-secure/safexcel_cipher.c b/drivers/crypto/inside-secure/safexcel_cipher.c index bafb60505fab..6bb60fda2043 100644 --- a/drivers/crypto/inside-secure/safexcel_cipher.c +++ b/drivers/crypto/inside-secure/safexcel_cipher.c @@ -12,8 +12,12 @@ #include <linux/dma-mapping.h> #include <linux/dmapool.h> +#include <crypto/aead.h> #include <crypto/aes.h> +#include <crypto/authenc.h> +#include <crypto/sha.h> #include <crypto/skcipher.h> +#include <crypto/internal/aead.h> #include <crypto/internal/skcipher.h> #include "safexcel.h" @@ -28,9 +32,16 @@ struct safexcel_cipher_ctx { struct safexcel_crypto_priv *priv; u32 mode; + bool aead; __le32 key[8]; unsigned int key_len; + + /* All the below is AEAD specific */ + u32 alg; + u32 state_sz; + u32 ipad[SHA256_DIGEST_SIZE / sizeof(u32)]; + u32 opad[SHA256_DIGEST_SIZE / sizeof(u32)]; }; struct safexcel_cipher_req { @@ -38,18 +49,16 @@ struct safexcel_cipher_req { bool needs_inv; }; -static void safexcel_cipher_token(struct safexcel_cipher_ctx *ctx, - struct crypto_async_request *async, - struct safexcel_command_desc *cdesc, - u32 length) +static void safexcel_skcipher_token(struct safexcel_cipher_ctx *ctx, u8 *iv, + struct safexcel_command_desc *cdesc, + u32 length) { - struct skcipher_request *req = skcipher_request_cast(async); struct safexcel_token *token; unsigned offset = 0; if (ctx->mode == CONTEXT_CONTROL_CRYPTO_MODE_CBC) { offset = AES_BLOCK_SIZE / sizeof(u32); - memcpy(cdesc->control_data.token, req->iv, AES_BLOCK_SIZE); + memcpy(cdesc->control_data.token, iv, AES_BLOCK_SIZE); cdesc->control_data.options |= EIP197_OPTION_4_TOKEN_IV_CMD; } @@ -65,8 +74,64 @@ static void safexcel_cipher_token(struct safexcel_cipher_ctx *ctx, EIP197_TOKEN_INS_TYPE_OUTPUT; } -static int safexcel_aes_setkey(struct crypto_skcipher *ctfm, const u8 *key, - unsigned int len) +static void safexcel_aead_token(struct safexcel_cipher_ctx *ctx, u8 *iv, + struct safexcel_command_desc *cdesc, + enum safexcel_cipher_direction direction, + u32 cryptlen, u32 assoclen, u32 digestsize) +{ + struct safexcel_token *token; + unsigned offset = 0; + + if (ctx->mode == CONTEXT_CONTROL_CRYPTO_MODE_CBC) { + offset = AES_BLOCK_SIZE / sizeof(u32); + memcpy(cdesc->control_data.token, iv, AES_BLOCK_SIZE); + + cdesc->control_data.options |= EIP197_OPTION_4_TOKEN_IV_CMD; + } + + token = (struct safexcel_token *)(cdesc->control_data.token + offset); + + if (direction == SAFEXCEL_DECRYPT) + cryptlen -= digestsize; + + token[0].opcode = EIP197_TOKEN_OPCODE_DIRECTION; + token[0].packet_length = assoclen; + token[0].instructions = EIP197_TOKEN_INS_TYPE_HASH | + EIP197_TOKEN_INS_TYPE_OUTPUT; + + token[1].opcode = EIP197_TOKEN_OPCODE_DIRECTION; + token[1].packet_length = cryptlen; + token[1].stat = EIP197_TOKEN_STAT_LAST_HASH; + token[1].instructions = EIP197_TOKEN_INS_LAST | + EIP197_TOKEN_INS_TYPE_CRYTO | + EIP197_TOKEN_INS_TYPE_HASH | + EIP197_TOKEN_INS_TYPE_OUTPUT; + + if (direction == SAFEXCEL_ENCRYPT) { + token[2].opcode = EIP197_TOKEN_OPCODE_INSERT; + token[2].packet_length = digestsize; + token[2].stat = EIP197_TOKEN_STAT_LAST_HASH | + EIP197_TOKEN_STAT_LAST_PACKET; + token[2].instructions = EIP197_TOKEN_INS_TYPE_OUTPUT | + EIP197_TOKEN_INS_INSERT_HASH_DIGEST; + } else { + token[2].opcode = EIP197_TOKEN_OPCODE_RETRIEVE; + token[2].packet_length = digestsize; + token[2].stat = EIP197_TOKEN_STAT_LAST_HASH | + EIP197_TOKEN_STAT_LAST_PACKET; + token[2].instructions = EIP197_TOKEN_INS_INSERT_HASH_DIGEST; + + token[3].opcode = EIP197_TOKEN_OPCODE_VERIFY; + token[3].packet_length = digestsize | + EIP197_TOKEN_HASH_RESULT_VERIFY; + token[3].stat = EIP197_TOKEN_STAT_LAST_HASH | + EIP197_TOKEN_STAT_LAST_PACKET; + token[3].instructions = EIP197_TOKEN_INS_TYPE_OUTPUT; + } +} + +static int safexcel_skcipher_aes_setkey(struct crypto_skcipher *ctfm, + const u8 *key, unsigned int len) { struct crypto_tfm *tfm = crypto_skcipher_tfm(ctfm); struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); @@ -98,41 +163,123 @@ static int safexcel_aes_setkey(struct crypto_skcipher *ctfm, const u8 *key, return 0; } +static int safexcel_aead_aes_setkey(struct crypto_aead *ctfm, const u8 *key, + unsigned int len) +{ + struct crypto_tfm *tfm = crypto_aead_tfm(ctfm); + struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); + struct safexcel_ahash_export_state istate, ostate; + struct safexcel_crypto_priv *priv = ctx->priv; + struct crypto_authenc_keys keys; + + if (crypto_authenc_extractkeys(&keys, key, len) != 0) + goto badkey; + + if (keys.enckeylen > sizeof(ctx->key)) + goto badkey; + + /* Encryption key */ + if (priv->version == EIP197 && ctx->base.ctxr_dma && + memcmp(ctx->key, keys.enckey, keys.enckeylen)) + ctx->base.needs_inv = true; + + /* Auth key */ + switch (ctx->alg) { + case CONTEXT_CONTROL_CRYPTO_ALG_SHA1: + if (safexcel_hmac_setkey("safexcel-sha1", keys.authkey, + keys.authkeylen, &istate, &ostate)) + goto badkey; + break; + case CONTEXT_CONTROL_CRYPTO_ALG_SHA224: + if (safexcel_hmac_setkey("safexcel-sha224", keys.authkey, + keys.authkeylen, &istate, &ostate)) + goto badkey; + break; + case CONTEXT_CONTROL_CRYPTO_ALG_SHA256: + if (safexcel_hmac_setkey("safexcel-sha256", keys.authkey, + keys.authkeylen, &istate, &ostate)) + goto badkey; + break; + default: + dev_err(priv->dev, "aead: unsupported hash algorithm\n"); + goto badkey; + } + + crypto_aead_set_flags(ctfm, crypto_aead_get_flags(ctfm) & + CRYPTO_TFM_RES_MASK); + + if (priv->version == EIP197 && ctx->base.ctxr_dma && + (memcmp(ctx->ipad, istate.state, ctx->state_sz) || + memcmp(ctx->opad, ostate.state, ctx->state_sz))) + ctx->base.needs_inv = true; + + /* Now copy the keys into the context */ + memcpy(ctx->key, keys.enckey, keys.enckeylen); + ctx->key_len = keys.enckeylen; + + memcpy(ctx->ipad, &istate.state, ctx->state_sz); + memcpy(ctx->opad, &ostate.state, ctx->state_sz); + + memzero_explicit(&keys, sizeof(keys)); + return 0; + +badkey: + crypto_aead_set_flags(ctfm, CRYPTO_TFM_RES_BAD_KEY_LEN); + memzero_explicit(&keys, sizeof(keys)); + return -EINVAL; +} + static int safexcel_context_control(struct safexcel_cipher_ctx *ctx, struct crypto_async_request *async, + struct safexcel_cipher_req *sreq, struct safexcel_command_desc *cdesc) { struct safexcel_crypto_priv *priv = ctx->priv; - struct skcipher_request *req = skcipher_request_cast(async); - struct safexcel_cipher_req *sreq = skcipher_request_ctx(req); int ctrl_size; - if (sreq->direction == SAFEXCEL_ENCRYPT) + if (ctx->aead) { + if (sreq->direction == SAFEXCEL_ENCRYPT) + cdesc->control_data.control0 |= CONTEXT_CONTROL_TYPE_ENCRYPT_HASH_OUT; + else + cdesc->control_data.control0 |= CONTEXT_CONTROL_TYPE_HASH_DECRYPT_IN; + } else { cdesc->control_data.control0 |= CONTEXT_CONTROL_TYPE_CRYPTO_OUT; - else - cdesc->control_data.control0 |= CONTEXT_CONTROL_TYPE_CRYPTO_IN; + + /* The decryption control type is a combination of the + * encryption type and CONTEXT_CONTROL_TYPE_NULL_IN, for all + * types. + */ + if (sreq->direction == SAFEXCEL_DECRYPT) + cdesc->control_data.control0 |= CONTEXT_CONTROL_TYPE_NULL_IN; + } cdesc->control_data.control0 |= CONTEXT_CONTROL_KEY_EN; cdesc->control_data.control1 |= ctx->mode; + if (ctx->aead) + cdesc->control_data.control0 |= CONTEXT_CONTROL_DIGEST_HMAC | + ctx->alg; + switch (ctx->key_len) { case AES_KEYSIZE_128: cdesc->control_data.control0 |= CONTEXT_CONTROL_CRYPTO_ALG_AES128; - ctrl_size = 4; break; case AES_KEYSIZE_192: cdesc->control_data.control0 |= CONTEXT_CONTROL_CRYPTO_ALG_AES192; - ctrl_size = 6; break; case AES_KEYSIZE_256: cdesc->control_data.control0 |= CONTEXT_CONTROL_CRYPTO_ALG_AES256; - ctrl_size = 8; break; default: dev_err(priv->dev, "aes keysize not supported: %u\n", ctx->key_len); return -EINVAL; } + + ctrl_size = ctx->key_len / sizeof(u32); + if (ctx->aead) + /* Take in account the ipad+opad digests */ + ctrl_size += ctx->state_sz / sizeof(u32) * 2; cdesc->control_data.control0 |= CONTEXT_CONTROL_SIZE(ctrl_size); return 0; @@ -140,9 +287,12 @@ static int safexcel_context_control(struct safexcel_cipher_ctx *ctx, static int safexcel_handle_req_result(struct safexcel_crypto_priv *priv, int ring, struct crypto_async_request *async, + struct scatterlist *src, + struct scatterlist *dst, + unsigned int cryptlen, + struct safexcel_cipher_req *sreq, bool *should_complete, int *ret) { - struct skcipher_request *req = skcipher_request_cast(async); struct safexcel_result_desc *rdesc; int ndesc = 0; @@ -158,12 +308,8 @@ static int safexcel_handle_req_result(struct safexcel_crypto_priv *priv, int rin break; } - if (rdesc->result_data.error_code) { - dev_err(priv->dev, - "cipher: result: result descriptor error (%d)\n", - rdesc->result_data.error_code); - *ret = -EIO; - } + if (likely(!*ret)) + *ret = safexcel_rdesc_check_errors(priv, rdesc); ndesc++; } while (!rdesc->last_seg); @@ -171,16 +317,16 @@ static int safexcel_handle_req_result(struct safexcel_crypto_priv *priv, int rin safexcel_complete(priv, ring); spin_unlock_bh(&priv->ring[ring].egress_lock); - if (req->src == req->dst) { - dma_unmap_sg(priv->dev, req->src, - sg_nents_for_len(req->src, req->cryptlen), + if (src == dst) { + dma_unmap_sg(priv->dev, src, + sg_nents_for_len(src, cryptlen), DMA_BIDIRECTIONAL); } else { - dma_unmap_sg(priv->dev, req->src, - sg_nents_for_len(req->src, req->cryptlen), + dma_unmap_sg(priv->dev, src, + sg_nents_for_len(src, cryptlen), DMA_TO_DEVICE); - dma_unmap_sg(priv->dev, req->dst, - sg_nents_for_len(req->dst, req->cryptlen), + dma_unmap_sg(priv->dev, dst, + sg_nents_for_len(dst, cryptlen), DMA_FROM_DEVICE); } @@ -189,39 +335,43 @@ static int safexcel_handle_req_result(struct safexcel_crypto_priv *priv, int rin return ndesc; } -static int safexcel_aes_send(struct crypto_async_request *async, - int ring, struct safexcel_request *request, - int *commands, int *results) +static int safexcel_aes_send(struct crypto_async_request *base, int ring, + struct safexcel_request *request, + struct safexcel_cipher_req *sreq, + struct scatterlist *src, struct scatterlist *dst, + unsigned int cryptlen, unsigned int assoclen, + unsigned int digestsize, u8 *iv, int *commands, + int *results) { - struct skcipher_request *req = skcipher_request_cast(async); - struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(req->base.tfm); + struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(base->tfm); struct safexcel_crypto_priv *priv = ctx->priv; struct safexcel_command_desc *cdesc; struct safexcel_result_desc *rdesc; struct scatterlist *sg; - int nr_src, nr_dst, n_cdesc = 0, n_rdesc = 0, queued = req->cryptlen; + unsigned int totlen = cryptlen + assoclen; + int nr_src, nr_dst, n_cdesc = 0, n_rdesc = 0, queued = totlen; int i, ret = 0; - if (req->src == req->dst) { - nr_src = dma_map_sg(priv->dev, req->src, - sg_nents_for_len(req->src, req->cryptlen), + if (src == dst) { + nr_src = dma_map_sg(priv->dev, src, + sg_nents_for_len(src, totlen), DMA_BIDIRECTIONAL); nr_dst = nr_src; if (!nr_src) return -EINVAL; } else { - nr_src = dma_map_sg(priv->dev, req->src, - sg_nents_for_len(req->src, req->cryptlen), + nr_src = dma_map_sg(priv->dev, src, + sg_nents_for_len(src, totlen), DMA_TO_DEVICE); if (!nr_src) return -EINVAL; - nr_dst = dma_map_sg(priv->dev, req->dst, - sg_nents_for_len(req->dst, req->cryptlen), + nr_dst = dma_map_sg(priv->dev, dst, + sg_nents_for_len(dst, totlen), DMA_FROM_DEVICE); if (!nr_dst) { - dma_unmap_sg(priv->dev, req->src, - sg_nents_for_len(req->src, req->cryptlen), + dma_unmap_sg(priv->dev, src, + sg_nents_for_len(src, totlen), DMA_TO_DEVICE); return -EINVAL; } @@ -229,10 +379,17 @@ static int safexcel_aes_send(struct crypto_async_request *async, memcpy(ctx->base.ctxr->data, ctx->key, ctx->key_len); + if (ctx->aead) { + memcpy(ctx->base.ctxr->data + ctx->key_len / sizeof(u32), + ctx->ipad, ctx->state_sz); + memcpy(ctx->base.ctxr->data + (ctx->key_len + ctx->state_sz) / sizeof(u32), + ctx->opad, ctx->state_sz); + } + spin_lock_bh(&priv->ring[ring].egress_lock); /* command descriptors */ - for_each_sg(req->src, sg, nr_src, i) { + for_each_sg(src, sg, nr_src, i) { int len = sg_dma_len(sg); /* Do not overflow the request */ @@ -240,7 +397,7 @@ static int safexcel_aes_send(struct crypto_async_request *async, len = queued; cdesc = safexcel_add_cdesc(priv, ring, !n_cdesc, !(queued - len), - sg_dma_address(sg), len, req->cryptlen, + sg_dma_address(sg), len, totlen, ctx->base.ctxr_dma); if (IS_ERR(cdesc)) { /* No space left in the command descriptor ring */ @@ -250,8 +407,14 @@ static int safexcel_aes_send(struct crypto_async_request *async, n_cdesc++; if (n_cdesc == 1) { - safexcel_context_control(ctx, async, cdesc); - safexcel_cipher_token(ctx, async, cdesc, req->cryptlen); + safexcel_context_control(ctx, base, sreq, cdesc); + if (ctx->aead) + safexcel_aead_token(ctx, iv, cdesc, + sreq->direction, cryptlen, + assoclen, digestsize); + else + safexcel_skcipher_token(ctx, iv, cdesc, + cryptlen); } queued -= len; @@ -260,7 +423,7 @@ static int safexcel_aes_send(struct crypto_async_request *async, } /* result descriptors */ - for_each_sg(req->dst, sg, nr_dst, i) { + for_each_sg(dst, sg, nr_dst, i) { bool first = !i, last = (i == nr_dst - 1); u32 len = sg_dma_len(sg); @@ -276,7 +439,7 @@ static int safexcel_aes_send(struct crypto_async_request *async, spin_unlock_bh(&priv->ring[ring].egress_lock); - request->req = &req->base; + request->req = base; *commands = n_cdesc; *results = n_rdesc; @@ -291,16 +454,16 @@ cdesc_rollback: spin_unlock_bh(&priv->ring[ring].egress_lock); - if (req->src == req->dst) { - dma_unmap_sg(priv->dev, req->src, - sg_nents_for_len(req->src, req->cryptlen), + if (src == dst) { + dma_unmap_sg(priv->dev, src, + sg_nents_for_len(src, totlen), DMA_BIDIRECTIONAL); } else { - dma_unmap_sg(priv->dev, req->src, - sg_nents_for_len(req->src, req->cryptlen), + dma_unmap_sg(priv->dev, src, + sg_nents_for_len(src, totlen), DMA_TO_DEVICE); - dma_unmap_sg(priv->dev, req->dst, - sg_nents_for_len(req->dst, req->cryptlen), + dma_unmap_sg(priv->dev, dst, + sg_nents_for_len(dst, totlen), DMA_FROM_DEVICE); } @@ -309,11 +472,10 @@ cdesc_rollback: static int safexcel_handle_inv_result(struct safexcel_crypto_priv *priv, int ring, - struct crypto_async_request *async, + struct crypto_async_request *base, bool *should_complete, int *ret) { - struct skcipher_request *req = skcipher_request_cast(async); - struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(req->base.tfm); + struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(base->tfm); struct safexcel_result_desc *rdesc; int ndesc = 0, enq_ret; @@ -354,7 +516,7 @@ static int safexcel_handle_inv_result(struct safexcel_crypto_priv *priv, ctx->base.ring = ring; spin_lock_bh(&priv->ring[ring].queue_lock); - enq_ret = crypto_enqueue_request(&priv->ring[ring].queue, async); + enq_ret = crypto_enqueue_request(&priv->ring[ring].queue, base); spin_unlock_bh(&priv->ring[ring].queue_lock); if (enq_ret != -EINPROGRESS) @@ -368,9 +530,10 @@ static int safexcel_handle_inv_result(struct safexcel_crypto_priv *priv, return ndesc; } -static int safexcel_handle_result(struct safexcel_crypto_priv *priv, int ring, - struct crypto_async_request *async, - bool *should_complete, int *ret) +static int safexcel_skcipher_handle_result(struct safexcel_crypto_priv *priv, + int ring, + struct crypto_async_request *async, + bool *should_complete, int *ret) { struct skcipher_request *req = skcipher_request_cast(async); struct safexcel_cipher_req *sreq = skcipher_request_ctx(req); @@ -381,24 +544,48 @@ static int safexcel_handle_result(struct safexcel_crypto_priv *priv, int ring, err = safexcel_handle_inv_result(priv, ring, async, should_complete, ret); } else { - err = safexcel_handle_req_result(priv, ring, async, + err = safexcel_handle_req_result(priv, ring, async, req->src, + req->dst, req->cryptlen, sreq, should_complete, ret); } return err; } -static int safexcel_cipher_send_inv(struct crypto_async_request *async, +static int safexcel_aead_handle_result(struct safexcel_crypto_priv *priv, + int ring, + struct crypto_async_request *async, + bool *should_complete, int *ret) +{ + struct aead_request *req = aead_request_cast(async); + struct crypto_aead *tfm = crypto_aead_reqtfm(req); + struct safexcel_cipher_req *sreq = aead_request_ctx(req); + int err; + + if (sreq->needs_inv) { + sreq->needs_inv = false; + err = safexcel_handle_inv_result(priv, ring, async, + should_complete, ret); + } else { + err = safexcel_handle_req_result(priv, ring, async, req->src, + req->dst, + req->cryptlen + crypto_aead_authsize(tfm), + sreq, should_complete, ret); + } + + return err; +} + +static int safexcel_cipher_send_inv(struct crypto_async_request *base, int ring, struct safexcel_request *request, int *commands, int *results) { - struct skcipher_request *req = skcipher_request_cast(async); - struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(req->base.tfm); + struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(base->tfm); struct safexcel_crypto_priv *priv = ctx->priv; int ret; - ret = safexcel_invalidate_cache(async, priv, - ctx->base.ctxr_dma, ring, request); + ret = safexcel_invalidate_cache(base, priv, ctx->base.ctxr_dma, ring, + request); if (unlikely(ret)) return ret; @@ -408,9 +595,9 @@ static int safexcel_cipher_send_inv(struct crypto_async_request *async, return 0; } -static int safexcel_send(struct crypto_async_request *async, - int ring, struct safexcel_request *request, - int *commands, int *results) +static int safexcel_skcipher_send(struct crypto_async_request *async, int ring, + struct safexcel_request *request, + int *commands, int *results) { struct skcipher_request *req = skcipher_request_cast(async); struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(req->base.tfm); @@ -421,59 +608,108 @@ static int safexcel_send(struct crypto_async_request *async, BUG_ON(priv->version == EIP97 && sreq->needs_inv); if (sreq->needs_inv) - ret = safexcel_cipher_send_inv(async, ring, request, - commands, results); + ret = safexcel_cipher_send_inv(async, ring, request, commands, + results); + else + ret = safexcel_aes_send(async, ring, request, sreq, req->src, + req->dst, req->cryptlen, 0, 0, req->iv, + commands, results); + return ret; +} + +static int safexcel_aead_send(struct crypto_async_request *async, int ring, + struct safexcel_request *request, int *commands, + int *results) +{ + struct aead_request *req = aead_request_cast(async); + struct crypto_aead *tfm = crypto_aead_reqtfm(req); + struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(req->base.tfm); + struct safexcel_cipher_req *sreq = aead_request_ctx(req); + struct safexcel_crypto_priv *priv = ctx->priv; + int ret; + + BUG_ON(priv->version == EIP97 && sreq->needs_inv); + + if (sreq->needs_inv) + ret = safexcel_cipher_send_inv(async, ring, request, commands, + results); else - ret = safexcel_aes_send(async, ring, request, + ret = safexcel_aes_send(async, ring, request, sreq, req->src, + req->dst, req->cryptlen, req->assoclen, + crypto_aead_authsize(tfm), req->iv, commands, results); return ret; } -static int safexcel_cipher_exit_inv(struct crypto_tfm *tfm) +static int safexcel_cipher_exit_inv(struct crypto_tfm *tfm, + struct crypto_async_request *base, + struct safexcel_cipher_req *sreq, + struct safexcel_inv_result *result) { struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); struct safexcel_crypto_priv *priv = ctx->priv; - SKCIPHER_REQUEST_ON_STACK(req, __crypto_skcipher_cast(tfm)); - struct safexcel_cipher_req *sreq = skcipher_request_ctx(req); - struct safexcel_inv_result result = {}; int ring = ctx->base.ring; - memset(req, 0, sizeof(struct skcipher_request)); + init_completion(&result->completion); - /* create invalidation request */ - init_completion(&result.completion); - skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, - safexcel_inv_complete, &result); - - skcipher_request_set_tfm(req, __crypto_skcipher_cast(tfm)); - ctx = crypto_tfm_ctx(req->base.tfm); + ctx = crypto_tfm_ctx(base->tfm); ctx->base.exit_inv = true; sreq->needs_inv = true; spin_lock_bh(&priv->ring[ring].queue_lock); - crypto_enqueue_request(&priv->ring[ring].queue, &req->base); + crypto_enqueue_request(&priv->ring[ring].queue, base); spin_unlock_bh(&priv->ring[ring].queue_lock); queue_work(priv->ring[ring].workqueue, &priv->ring[ring].work_data.work); - wait_for_completion(&result.completion); + wait_for_completion(&result->completion); - if (result.error) { + if (result->error) { dev_warn(priv->dev, "cipher: sync: invalidate: completion error %d\n", - result.error); - return result.error; + result->error); + return result->error; } return 0; } -static int safexcel_aes(struct skcipher_request *req, - enum safexcel_cipher_direction dir, u32 mode) +static int safexcel_skcipher_exit_inv(struct crypto_tfm *tfm) { - struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(req->base.tfm); + EIP197_REQUEST_ON_STACK(req, skcipher, EIP197_SKCIPHER_REQ_SIZE); struct safexcel_cipher_req *sreq = skcipher_request_ctx(req); + struct safexcel_inv_result result = {}; + + memset(req, 0, sizeof(struct skcipher_request)); + + skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, + safexcel_inv_complete, &result); + skcipher_request_set_tfm(req, __crypto_skcipher_cast(tfm)); + + return safexcel_cipher_exit_inv(tfm, &req->base, sreq, &result); +} + +static int safexcel_aead_exit_inv(struct crypto_tfm *tfm) +{ + EIP197_REQUEST_ON_STACK(req, aead, EIP197_AEAD_REQ_SIZE); + struct safexcel_cipher_req *sreq = aead_request_ctx(req); + struct safexcel_inv_result result = {}; + + memset(req, 0, sizeof(struct aead_request)); + + aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, + safexcel_inv_complete, &result); + aead_request_set_tfm(req, __crypto_aead_cast(tfm)); + + return safexcel_cipher_exit_inv(tfm, &req->base, sreq, &result); +} + +static int safexcel_aes(struct crypto_async_request *base, + struct safexcel_cipher_req *sreq, + enum safexcel_cipher_direction dir, u32 mode) +{ + struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(base->tfm); struct safexcel_crypto_priv *priv = ctx->priv; int ret, ring; @@ -489,7 +725,7 @@ static int safexcel_aes(struct skcipher_request *req, } else { ctx->base.ring = safexcel_select_ring(priv); ctx->base.ctxr = dma_pool_zalloc(priv->context_pool, - EIP197_GFP_FLAGS(req->base), + EIP197_GFP_FLAGS(*base), &ctx->base.ctxr_dma); if (!ctx->base.ctxr) return -ENOMEM; @@ -498,7 +734,7 @@ static int safexcel_aes(struct skcipher_request *req, ring = ctx->base.ring; spin_lock_bh(&priv->ring[ring].queue_lock); - ret = crypto_enqueue_request(&priv->ring[ring].queue, &req->base); + ret = crypto_enqueue_request(&priv->ring[ring].queue, base); spin_unlock_bh(&priv->ring[ring].queue_lock); queue_work(priv->ring[ring].workqueue, @@ -509,14 +745,14 @@ static int safexcel_aes(struct skcipher_request *req, static int safexcel_ecb_aes_encrypt(struct skcipher_request *req) { - return safexcel_aes(req, SAFEXCEL_ENCRYPT, - CONTEXT_CONTROL_CRYPTO_MODE_ECB); + return safexcel_aes(&req->base, skcipher_request_ctx(req), + SAFEXCEL_ENCRYPT, CONTEXT_CONTROL_CRYPTO_MODE_ECB); } static int safexcel_ecb_aes_decrypt(struct skcipher_request *req) { - return safexcel_aes(req, SAFEXCEL_DECRYPT, - CONTEXT_CONTROL_CRYPTO_MODE_ECB); + return safexcel_aes(&req->base, skcipher_request_ctx(req), + SAFEXCEL_DECRYPT, CONTEXT_CONTROL_CRYPTO_MODE_ECB); } static int safexcel_skcipher_cra_init(struct crypto_tfm *tfm) @@ -526,34 +762,64 @@ static int safexcel_skcipher_cra_init(struct crypto_tfm *tfm) container_of(tfm->__crt_alg, struct safexcel_alg_template, alg.skcipher.base); - ctx->priv = tmpl->priv; - ctx->base.send = safexcel_send; - ctx->base.handle_result = safexcel_handle_result; - crypto_skcipher_set_reqsize(__crypto_skcipher_cast(tfm), sizeof(struct safexcel_cipher_req)); + ctx->priv = tmpl->priv; + + ctx->base.send = safexcel_skcipher_send; + ctx->base.handle_result = safexcel_skcipher_handle_result; return 0; } -static void safexcel_skcipher_cra_exit(struct crypto_tfm *tfm) +static int safexcel_cipher_cra_exit(struct crypto_tfm *tfm) { struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); - struct safexcel_crypto_priv *priv = ctx->priv; - int ret; - memzero_explicit(ctx->key, 8 * sizeof(u32)); + memzero_explicit(ctx->key, sizeof(ctx->key)); /* context not allocated, skip invalidation */ if (!ctx->base.ctxr) + return -ENOMEM; + + memzero_explicit(ctx->base.ctxr->data, sizeof(ctx->base.ctxr->data)); + return 0; +} + +static void safexcel_skcipher_cra_exit(struct crypto_tfm *tfm) +{ + struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); + struct safexcel_crypto_priv *priv = ctx->priv; + int ret; + + if (safexcel_cipher_cra_exit(tfm)) return; - memzero_explicit(ctx->base.ctxr->data, 8 * sizeof(u32)); + if (priv->version == EIP197) { + ret = safexcel_skcipher_exit_inv(tfm); + if (ret) + dev_warn(priv->dev, "skcipher: invalidation error %d\n", + ret); + } else { + dma_pool_free(priv->context_pool, ctx->base.ctxr, + ctx->base.ctxr_dma); + } +} + +static void safexcel_aead_cra_exit(struct crypto_tfm *tfm) +{ + struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); + struct safexcel_crypto_priv *priv = ctx->priv; + int ret; + + if (safexcel_cipher_cra_exit(tfm)) + return; if (priv->version == EIP197) { - ret = safexcel_cipher_exit_inv(tfm); + ret = safexcel_aead_exit_inv(tfm); if (ret) - dev_warn(priv->dev, "cipher: invalidation error %d\n", ret); + dev_warn(priv->dev, "aead: invalidation error %d\n", + ret); } else { dma_pool_free(priv->context_pool, ctx->base.ctxr, ctx->base.ctxr_dma); @@ -563,7 +829,7 @@ static void safexcel_skcipher_cra_exit(struct crypto_tfm *tfm) struct safexcel_alg_template safexcel_alg_ecb_aes = { .type = SAFEXCEL_ALG_TYPE_SKCIPHER, .alg.skcipher = { - .setkey = safexcel_aes_setkey, + .setkey = safexcel_skcipher_aes_setkey, .encrypt = safexcel_ecb_aes_encrypt, .decrypt = safexcel_ecb_aes_decrypt, .min_keysize = AES_MIN_KEY_SIZE, @@ -586,20 +852,20 @@ struct safexcel_alg_template safexcel_alg_ecb_aes = { static int safexcel_cbc_aes_encrypt(struct skcipher_request *req) { - return safexcel_aes(req, SAFEXCEL_ENCRYPT, - CONTEXT_CONTROL_CRYPTO_MODE_CBC); + return safexcel_aes(&req->base, skcipher_request_ctx(req), + SAFEXCEL_ENCRYPT, CONTEXT_CONTROL_CRYPTO_MODE_CBC); } static int safexcel_cbc_aes_decrypt(struct skcipher_request *req) { - return safexcel_aes(req, SAFEXCEL_DECRYPT, - CONTEXT_CONTROL_CRYPTO_MODE_CBC); + return safexcel_aes(&req->base, skcipher_request_ctx(req), + SAFEXCEL_DECRYPT, CONTEXT_CONTROL_CRYPTO_MODE_CBC); } struct safexcel_alg_template safexcel_alg_cbc_aes = { .type = SAFEXCEL_ALG_TYPE_SKCIPHER, .alg.skcipher = { - .setkey = safexcel_aes_setkey, + .setkey = safexcel_skcipher_aes_setkey, .encrypt = safexcel_cbc_aes_encrypt, .decrypt = safexcel_cbc_aes_decrypt, .min_keysize = AES_MIN_KEY_SIZE, @@ -620,3 +886,139 @@ struct safexcel_alg_template safexcel_alg_cbc_aes = { }, }, }; + +static int safexcel_aead_encrypt(struct aead_request *req) +{ + struct safexcel_cipher_req *creq = aead_request_ctx(req); + + return safexcel_aes(&req->base, creq, SAFEXCEL_ENCRYPT, + CONTEXT_CONTROL_CRYPTO_MODE_CBC); +} + +static int safexcel_aead_decrypt(struct aead_request *req) +{ + struct safexcel_cipher_req *creq = aead_request_ctx(req); + + return safexcel_aes(&req->base, creq, SAFEXCEL_DECRYPT, + CONTEXT_CONTROL_CRYPTO_MODE_CBC); +} + +static int safexcel_aead_cra_init(struct crypto_tfm *tfm) +{ + struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); + struct safexcel_alg_template *tmpl = + container_of(tfm->__crt_alg, struct safexcel_alg_template, + alg.aead.base); + + crypto_aead_set_reqsize(__crypto_aead_cast(tfm), + sizeof(struct safexcel_cipher_req)); + + ctx->priv = tmpl->priv; + + ctx->aead = true; + ctx->base.send = safexcel_aead_send; + ctx->base.handle_result = safexcel_aead_handle_result; + return 0; +} + +static int safexcel_aead_sha1_cra_init(struct crypto_tfm *tfm) +{ + struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); + + safexcel_aead_cra_init(tfm); + ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA1; + ctx->state_sz = SHA1_DIGEST_SIZE; + return 0; +} + +struct safexcel_alg_template safexcel_alg_authenc_hmac_sha1_cbc_aes = { + .type = SAFEXCEL_ALG_TYPE_AEAD, + .alg.aead = { + .setkey = safexcel_aead_aes_setkey, + .encrypt = safexcel_aead_encrypt, + .decrypt = safexcel_aead_decrypt, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA1_DIGEST_SIZE, + .base = { + .cra_name = "authenc(hmac(sha1),cbc(aes))", + .cra_driver_name = "safexcel-authenc-hmac-sha1-cbc-aes", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct safexcel_cipher_ctx), + .cra_alignmask = 0, + .cra_init = safexcel_aead_sha1_cra_init, + .cra_exit = safexcel_aead_cra_exit, + .cra_module = THIS_MODULE, + }, + }, +}; + +static int safexcel_aead_sha256_cra_init(struct crypto_tfm *tfm) +{ + struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); + + safexcel_aead_cra_init(tfm); + ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA256; + ctx->state_sz = SHA256_DIGEST_SIZE; + return 0; +} + +struct safexcel_alg_template safexcel_alg_authenc_hmac_sha256_cbc_aes = { + .type = SAFEXCEL_ALG_TYPE_AEAD, + .alg.aead = { + .setkey = safexcel_aead_aes_setkey, + .encrypt = safexcel_aead_encrypt, + .decrypt = safexcel_aead_decrypt, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA256_DIGEST_SIZE, + .base = { + .cra_name = "authenc(hmac(sha256),cbc(aes))", + .cra_driver_name = "safexcel-authenc-hmac-sha256-cbc-aes", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct safexcel_cipher_ctx), + .cra_alignmask = 0, + .cra_init = safexcel_aead_sha256_cra_init, + .cra_exit = safexcel_aead_cra_exit, + .cra_module = THIS_MODULE, + }, + }, +}; + +static int safexcel_aead_sha224_cra_init(struct crypto_tfm *tfm) +{ + struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); + + safexcel_aead_cra_init(tfm); + ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA224; + ctx->state_sz = SHA256_DIGEST_SIZE; + return 0; +} + +struct safexcel_alg_template safexcel_alg_authenc_hmac_sha224_cbc_aes = { + .type = SAFEXCEL_ALG_TYPE_AEAD, + .alg.aead = { + .setkey = safexcel_aead_aes_setkey, + .encrypt = safexcel_aead_encrypt, + .decrypt = safexcel_aead_decrypt, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA224_DIGEST_SIZE, + .base = { + .cra_name = "authenc(hmac(sha224),cbc(aes))", + .cra_driver_name = "safexcel-authenc-hmac-sha224-cbc-aes", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct safexcel_cipher_ctx), + .cra_alignmask = 0, + .cra_init = safexcel_aead_sha224_cra_init, + .cra_exit = safexcel_aead_cra_exit, + .cra_module = THIS_MODULE, + }, + }, +}; diff --git a/drivers/crypto/inside-secure/safexcel_hash.c b/drivers/crypto/inside-secure/safexcel_hash.c index 317b9e480312..d138d6b8fec5 100644 --- a/drivers/crypto/inside-secure/safexcel_hash.c +++ b/drivers/crypto/inside-secure/safexcel_hash.c @@ -50,16 +50,6 @@ struct safexcel_ahash_req { u8 cache_next[SHA256_BLOCK_SIZE] __aligned(sizeof(u32)); }; -struct safexcel_ahash_export_state { - u64 len; - u64 processed; - - u32 digest; - - u32 state[SHA256_DIGEST_SIZE / sizeof(u32)]; - u8 cache[SHA256_BLOCK_SIZE]; -}; - static void safexcel_hash_token(struct safexcel_command_desc *cdesc, u32 input_length, u32 result_length) { @@ -146,11 +136,8 @@ static int safexcel_handle_req_result(struct safexcel_crypto_priv *priv, int rin dev_err(priv->dev, "hash: result: could not retrieve the result descriptor\n"); *ret = PTR_ERR(rdesc); - } else if (rdesc->result_data.error_code) { - dev_err(priv->dev, - "hash: result: result descriptor error (%d)\n", - rdesc->result_data.error_code); - *ret = -EINVAL; + } else { + *ret = safexcel_rdesc_check_errors(priv, rdesc); } safexcel_complete(priv, ring); @@ -480,7 +467,7 @@ static int safexcel_ahash_exit_inv(struct crypto_tfm *tfm) { struct safexcel_ahash_ctx *ctx = crypto_tfm_ctx(tfm); struct safexcel_crypto_priv *priv = ctx->priv; - AHASH_REQUEST_ON_STACK(req, __crypto_ahash_cast(tfm)); + EIP197_REQUEST_ON_STACK(req, ahash, EIP197_AHASH_REQ_SIZE); struct safexcel_ahash_req *rctx = ahash_request_ctx(req); struct safexcel_inv_result result = {}; int ring = ctx->base.ring; @@ -912,8 +899,8 @@ static int safexcel_hmac_init_iv(struct ahash_request *areq, return crypto_ahash_export(areq, state); } -static int safexcel_hmac_setkey(const char *alg, const u8 *key, - unsigned int keylen, void *istate, void *ostate) +int safexcel_hmac_setkey(const char *alg, const u8 *key, unsigned int keylen, + void *istate, void *ostate) { struct ahash_request *areq; struct crypto_ahash *tfm; diff --git a/drivers/crypto/nx/nx-842-powernv.c b/drivers/crypto/nx/nx-842-powernv.c index 1e87637c412d..36afd6d8753c 100644 --- a/drivers/crypto/nx/nx-842-powernv.c +++ b/drivers/crypto/nx/nx-842-powernv.c @@ -334,7 +334,7 @@ static int wait_for_csb(struct nx842_workmem *wmem, return -EPROTO; case CSB_CC_SEQUENCE: /* should not happen, we don't use chained CRBs */ - CSB_ERR(csb, "CRB seqeunce number error"); + CSB_ERR(csb, "CRB sequence number error"); return -EPROTO; case CSB_CC_UNKNOWN_CODE: CSB_ERR(csb, "Unknown subfunction code"); diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c index ad02aa63b519..d1a1c74fb56a 100644 --- a/drivers/crypto/omap-sham.c +++ b/drivers/crypto/omap-sham.c @@ -1087,7 +1087,7 @@ static void omap_sham_finish_req(struct ahash_request *req, int err) if (test_bit(FLAGS_SGS_COPIED, &dd->flags)) free_pages((unsigned long)sg_virt(ctx->sg), - get_order(ctx->sg->length)); + get_order(ctx->sg->length + ctx->bufcnt)); if (test_bit(FLAGS_SGS_ALLOCED, &dd->flags)) kfree(ctx->sg); diff --git a/drivers/crypto/picoxcell_crypto.c b/drivers/crypto/picoxcell_crypto.c index a4df966adbf6..321d5e2ac833 100644 --- a/drivers/crypto/picoxcell_crypto.c +++ b/drivers/crypto/picoxcell_crypto.c @@ -1169,8 +1169,7 @@ static void spacc_spacc_complete(unsigned long data) #ifdef CONFIG_PM static int spacc_suspend(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct spacc_engine *engine = platform_get_drvdata(pdev); + struct spacc_engine *engine = dev_get_drvdata(dev); /* * We only support standby mode. All we have to do is gate the clock to @@ -1184,8 +1183,7 @@ static int spacc_suspend(struct device *dev) static int spacc_resume(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct spacc_engine *engine = platform_get_drvdata(pdev); + struct spacc_engine *engine = dev_get_drvdata(dev); return clk_enable(engine->clk); } diff --git a/drivers/crypto/qat/qat_c3xxx/adf_drv.c b/drivers/crypto/qat/qat_c3xxx/adf_drv.c index f172171668ee..ba197f34c252 100644 --- a/drivers/crypto/qat/qat_c3xxx/adf_drv.c +++ b/drivers/crypto/qat/qat_c3xxx/adf_drv.c @@ -329,5 +329,7 @@ module_exit(adfdrv_release); MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Intel"); +MODULE_FIRMWARE(ADF_C3XXX_FW); +MODULE_FIRMWARE(ADF_C3XXX_MMP); MODULE_DESCRIPTION("Intel(R) QuickAssist Technology"); MODULE_VERSION(ADF_DRV_VERSION); diff --git a/drivers/crypto/qat/qat_c62x/adf_drv.c b/drivers/crypto/qat/qat_c62x/adf_drv.c index 58a984c9c3ec..59a5a0df50b6 100644 --- a/drivers/crypto/qat/qat_c62x/adf_drv.c +++ b/drivers/crypto/qat/qat_c62x/adf_drv.c @@ -329,5 +329,7 @@ module_exit(adfdrv_release); MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Intel"); +MODULE_FIRMWARE(ADF_C62X_FW); +MODULE_FIRMWARE(ADF_C62X_MMP); MODULE_DESCRIPTION("Intel(R) QuickAssist Technology"); MODULE_VERSION(ADF_DRV_VERSION); diff --git a/drivers/crypto/qat/qat_dh895xcc/adf_drv.c b/drivers/crypto/qat/qat_dh895xcc/adf_drv.c index 2ce01f010c74..be5c5a988ca5 100644 --- a/drivers/crypto/qat/qat_dh895xcc/adf_drv.c +++ b/drivers/crypto/qat/qat_dh895xcc/adf_drv.c @@ -332,5 +332,6 @@ module_exit(adfdrv_release); MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Intel"); MODULE_FIRMWARE(ADF_DH895XCC_FW); +MODULE_FIRMWARE(ADF_DH895XCC_MMP); MODULE_DESCRIPTION("Intel(R) QuickAssist Technology"); MODULE_VERSION(ADF_DRV_VERSION); diff --git a/drivers/crypto/vmx/aes.c b/drivers/crypto/vmx/aes.c index 96072b9b55c4..d7316f7a3a69 100644 --- a/drivers/crypto/vmx/aes.c +++ b/drivers/crypto/vmx/aes.c @@ -48,8 +48,6 @@ static int p8_aes_init(struct crypto_tfm *tfm) alg, PTR_ERR(fallback)); return PTR_ERR(fallback); } - printk(KERN_INFO "Using '%s' as fallback implementation.\n", - crypto_tfm_alg_driver_name((struct crypto_tfm *) fallback)); crypto_cipher_set_flags(fallback, crypto_cipher_get_flags((struct diff --git a/drivers/crypto/vmx/aes_cbc.c b/drivers/crypto/vmx/aes_cbc.c index 7394d35d5936..5285ece4f33a 100644 --- a/drivers/crypto/vmx/aes_cbc.c +++ b/drivers/crypto/vmx/aes_cbc.c @@ -52,9 +52,6 @@ static int p8_aes_cbc_init(struct crypto_tfm *tfm) alg, PTR_ERR(fallback)); return PTR_ERR(fallback); } - printk(KERN_INFO "Using '%s' as fallback implementation.\n", - crypto_skcipher_driver_name(fallback)); - crypto_skcipher_set_flags( fallback, diff --git a/drivers/crypto/vmx/aes_ctr.c b/drivers/crypto/vmx/aes_ctr.c index fc60d00a2e84..cd777c75291d 100644 --- a/drivers/crypto/vmx/aes_ctr.c +++ b/drivers/crypto/vmx/aes_ctr.c @@ -50,8 +50,6 @@ static int p8_aes_ctr_init(struct crypto_tfm *tfm) alg, PTR_ERR(fallback)); return PTR_ERR(fallback); } - printk(KERN_INFO "Using '%s' as fallback implementation.\n", - crypto_skcipher_driver_name(fallback)); crypto_skcipher_set_flags( fallback, diff --git a/drivers/crypto/vmx/aes_xts.c b/drivers/crypto/vmx/aes_xts.c index 8cd6e62e4c90..8bd9aff0f55f 100644 --- a/drivers/crypto/vmx/aes_xts.c +++ b/drivers/crypto/vmx/aes_xts.c @@ -53,8 +53,6 @@ static int p8_aes_xts_init(struct crypto_tfm *tfm) alg, PTR_ERR(fallback)); return PTR_ERR(fallback); } - printk(KERN_INFO "Using '%s' as fallback implementation.\n", - crypto_skcipher_driver_name(fallback)); crypto_skcipher_set_flags( fallback, diff --git a/drivers/crypto/vmx/aesp8-ppc.pl b/drivers/crypto/vmx/aesp8-ppc.pl index 0b4a293b8a1e..d6a9f63d65ba 100644 --- a/drivers/crypto/vmx/aesp8-ppc.pl +++ b/drivers/crypto/vmx/aesp8-ppc.pl @@ -1,12 +1,51 @@ #! /usr/bin/env perl -# Copyright 2014-2016 The OpenSSL Project Authors. All Rights Reserved. +# SPDX-License-Identifier: GPL-2.0 + +# This code is taken from CRYPTOGAMs[1] and is included here using the option +# in the license to distribute the code under the GPL. Therefore 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. # -# Licensed under the OpenSSL license (the "License"). You may not use -# this file except in compliance with the License. You can obtain a copy -# in the file LICENSE in the source distribution or at -# https://www.openssl.org/source/license.html +# [1] https://www.openssl.org/~appro/cryptogams/ +# Copyright (c) 2006-2017, CRYPTOGAMS by <appro@openssl.org> +# 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 copyright notices, +# 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 of the CRYPTOGAMS nor the names of its +# copyright holder and 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 +# product may be distributed under the terms of the GNU General Public +# License (GPL), in which case the provisions of the GPL apply INSTEAD OF +# those given above. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER 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. + # ==================================================================== # Written by Andy Polyakov <appro@openssl.org> for the OpenSSL # project. The module is, however, dual licensed under OpenSSL and diff --git a/drivers/crypto/vmx/ghash.c b/drivers/crypto/vmx/ghash.c index 27a94a119009..1c4b5b889fba 100644 --- a/drivers/crypto/vmx/ghash.c +++ b/drivers/crypto/vmx/ghash.c @@ -64,8 +64,6 @@ static int p8_ghash_init_tfm(struct crypto_tfm *tfm) alg, PTR_ERR(fallback)); return PTR_ERR(fallback); } - printk(KERN_INFO "Using '%s' as fallback implementation.\n", - crypto_tfm_alg_driver_name(crypto_shash_tfm(fallback))); crypto_shash_set_flags(fallback, crypto_shash_get_flags((struct crypto_shash diff --git a/drivers/crypto/vmx/ghashp8-ppc.pl b/drivers/crypto/vmx/ghashp8-ppc.pl index d8429cb71f02..f746af271460 100644 --- a/drivers/crypto/vmx/ghashp8-ppc.pl +++ b/drivers/crypto/vmx/ghashp8-ppc.pl @@ -1,5 +1,14 @@ #!/usr/bin/env perl +# SPDX-License-Identifier: GPL-2.0 + +# This code is taken from the OpenSSL project but the author (Andy Polyakov) +# has relicensed it under the GPLv2. Therefore 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. # +# The original headers, including the original license headers, are +# included below for completeness. + # ==================================================================== # Written by Andy Polyakov <appro@openssl.org> for the OpenSSL # project. The module is, however, dual licensed under OpenSSL and diff --git a/drivers/dax/super.c b/drivers/dax/super.c index 2b2332b605e4..1d7bd96511f0 100644 --- a/drivers/dax/super.c +++ b/drivers/dax/super.c @@ -74,42 +74,42 @@ EXPORT_SYMBOL_GPL(fs_dax_get_by_bdev); /** * __bdev_dax_supported() - Check if the device supports dax for filesystem - * @sb: The superblock of the device + * @bdev: block device to check * @blocksize: The block size of the device * * This is a library function for filesystems to check if the block device * can be mounted with dax option. * - * Return: negative errno if unsupported, 0 if supported. + * Return: true if supported, false if unsupported */ -int __bdev_dax_supported(struct super_block *sb, int blocksize) +bool __bdev_dax_supported(struct block_device *bdev, int blocksize) { - struct block_device *bdev = sb->s_bdev; struct dax_device *dax_dev; pgoff_t pgoff; int err, id; void *kaddr; pfn_t pfn; long len; + char buf[BDEVNAME_SIZE]; if (blocksize != PAGE_SIZE) { - pr_debug("VFS (%s): error: unsupported blocksize for dax\n", - sb->s_id); - return -EINVAL; + pr_debug("%s: error: unsupported blocksize for dax\n", + bdevname(bdev, buf)); + return false; } err = bdev_dax_pgoff(bdev, 0, PAGE_SIZE, &pgoff); if (err) { - pr_debug("VFS (%s): error: unaligned partition for dax\n", - sb->s_id); - return err; + pr_debug("%s: error: unaligned partition for dax\n", + bdevname(bdev, buf)); + return false; } dax_dev = dax_get_by_host(bdev->bd_disk->disk_name); if (!dax_dev) { - pr_debug("VFS (%s): error: device does not support dax\n", - sb->s_id); - return -EOPNOTSUPP; + pr_debug("%s: error: device does not support dax\n", + bdevname(bdev, buf)); + return false; } id = dax_read_lock(); @@ -119,9 +119,9 @@ int __bdev_dax_supported(struct super_block *sb, int blocksize) put_dax(dax_dev); if (len < 1) { - pr_debug("VFS (%s): error: dax access failed (%ld)\n", - sb->s_id, len); - return len < 0 ? len : -EIO; + pr_debug("%s: error: dax access failed (%ld)\n", + bdevname(bdev, buf), len); + return false; } if (IS_ENABLED(CONFIG_FS_DAX_LIMITED) && pfn_t_special(pfn)) { @@ -137,12 +137,12 @@ int __bdev_dax_supported(struct super_block *sb, int blocksize) } else if (pfn_t_devmap(pfn)) { /* pass */; } else { - pr_debug("VFS (%s): error: dax support not enabled\n", - sb->s_id); - return -EOPNOTSUPP; + pr_debug("%s: error: dax support not enabled\n", + bdevname(bdev, buf)); + return false; } - return 0; + return true; } EXPORT_SYMBOL_GPL(__bdev_dax_supported); #endif diff --git a/drivers/dma/qcom/hidma_mgmt.c b/drivers/dma/qcom/hidma_mgmt.c index 000c7019ca7d..d64edeb6771a 100644 --- a/drivers/dma/qcom/hidma_mgmt.c +++ b/drivers/dma/qcom/hidma_mgmt.c @@ -398,7 +398,7 @@ static int __init hidma_mgmt_of_populate_channels(struct device_node *np) } of_node_get(child); new_pdev->dev.of_node = child; - of_dma_configure(&new_pdev->dev, child); + of_dma_configure(&new_pdev->dev, child, true); /* * It is assumed that calling of_msi_configure is safe on * platforms with or without MSI support. diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig index 3098410abad8..781a4a337557 100644 --- a/drivers/firmware/efi/Kconfig +++ b/drivers/firmware/efi/Kconfig @@ -174,6 +174,11 @@ config UEFI_CPER_ARM depends on UEFI_CPER && ( ARM || ARM64 ) default y +config UEFI_CPER_X86 + bool + depends on UEFI_CPER && X86 + default y + config EFI_DEV_PATH_PARSER bool depends on ACPI diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile index cb805374f4bc..5f9f5039de50 100644 --- a/drivers/firmware/efi/Makefile +++ b/drivers/firmware/efi/Makefile @@ -31,3 +31,4 @@ obj-$(CONFIG_ARM) += $(arm-obj-y) obj-$(CONFIG_ARM64) += $(arm-obj-y) obj-$(CONFIG_EFI_CAPSULE_LOADER) += capsule-loader.o obj-$(CONFIG_UEFI_CPER_ARM) += cper-arm.o +obj-$(CONFIG_UEFI_CPER_X86) += cper-x86.o diff --git a/drivers/firmware/efi/apple-properties.c b/drivers/firmware/efi/apple-properties.c index adaa9a3714b9..60a95719ecb8 100644 --- a/drivers/firmware/efi/apple-properties.c +++ b/drivers/firmware/efi/apple-properties.c @@ -13,6 +13,9 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Note, all properties are considered as u8 arrays. + * To get a value of any of them the caller must use device_property_read_u8_array(). */ #define pr_fmt(fmt) "apple-properties: " fmt @@ -96,12 +99,13 @@ static void __init unmarshal_key_value_pairs(struct dev_header *dev_header, entry[i].name = key; entry[i].length = val_len - sizeof(val_len); entry[i].is_array = !!entry[i].length; - entry[i].pointer.raw_data = ptr + key_len + sizeof(val_len); + entry[i].type = DEV_PROP_U8; + entry[i].pointer.u8_data = ptr + key_len + sizeof(val_len); if (dump_properties) { dev_info(dev, "property: %s\n", entry[i].name); print_hex_dump(KERN_INFO, pr_fmt(), DUMP_PREFIX_OFFSET, - 16, 1, entry[i].pointer.raw_data, + 16, 1, entry[i].pointer.u8_data, entry[i].length, true); } diff --git a/drivers/firmware/efi/capsule-loader.c b/drivers/firmware/efi/capsule-loader.c index e456f4602df1..96688986da56 100644 --- a/drivers/firmware/efi/capsule-loader.c +++ b/drivers/firmware/efi/capsule-loader.c @@ -134,10 +134,16 @@ static ssize_t efi_capsule_submit_update(struct capsule_info *cap_info) /* Indicate capsule binary uploading is done */ cap_info->index = NO_FURTHER_WRITE_ACTION; - pr_info("Successfully upload capsule file with reboot type '%s'\n", - !cap_info->reset_type ? "RESET_COLD" : - cap_info->reset_type == 1 ? "RESET_WARM" : - "RESET_SHUTDOWN"); + + if (cap_info->header.flags & EFI_CAPSULE_PERSIST_ACROSS_RESET) { + pr_info("Successfully uploaded capsule file with reboot type '%s'\n", + !cap_info->reset_type ? "RESET_COLD" : + cap_info->reset_type == 1 ? "RESET_WARM" : + "RESET_SHUTDOWN"); + } else { + pr_info("Successfully processed capsule file\n"); + } + return 0; } diff --git a/drivers/firmware/efi/cper-arm.c b/drivers/firmware/efi/cper-arm.c index 698e5c8e0c8d..502811344e81 100644 --- a/drivers/firmware/efi/cper-arm.c +++ b/drivers/firmware/efi/cper-arm.c @@ -30,8 +30,6 @@ #include <acpi/ghes.h> #include <ras/ras_event.h> -#define INDENT_SP " " - static const char * const arm_reg_ctx_strs[] = { "AArch32 general purpose registers", "AArch32 EL1 context registers", @@ -283,7 +281,7 @@ void cper_print_proc_arm(const char *pfx, pfx, proc->psci_state); } - snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP); + snprintf(newpfx, sizeof(newpfx), "%s ", pfx); err_info = (struct cper_arm_err_info *)(proc + 1); for (i = 0; i < proc->err_info_num; i++) { @@ -310,7 +308,7 @@ void cper_print_proc_arm(const char *pfx, if (err_info->validation_bits & CPER_ARM_INFO_VALID_ERR_INFO) { printk("%serror_info: 0x%016llx\n", newpfx, err_info->error_info); - snprintf(infopfx, sizeof(infopfx), "%s%s", newpfx, INDENT_SP); + snprintf(infopfx, sizeof(infopfx), "%s ", newpfx); cper_print_arm_err_info(infopfx, err_info->type, err_info->error_info); } diff --git a/drivers/firmware/efi/cper-x86.c b/drivers/firmware/efi/cper-x86.c new file mode 100644 index 000000000000..2531de49f56c --- /dev/null +++ b/drivers/firmware/efi/cper-x86.c @@ -0,0 +1,356 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2018, Advanced Micro Devices, Inc. + +#include <linux/cper.h> + +/* + * We don't need a "CPER_IA" prefix since these are all locally defined. + * This will save us a lot of line space. + */ +#define VALID_LAPIC_ID BIT_ULL(0) +#define VALID_CPUID_INFO BIT_ULL(1) +#define VALID_PROC_ERR_INFO_NUM(bits) (((bits) & GENMASK_ULL(7, 2)) >> 2) +#define VALID_PROC_CXT_INFO_NUM(bits) (((bits) & GENMASK_ULL(13, 8)) >> 8) + +#define INFO_ERR_STRUCT_TYPE_CACHE \ + GUID_INIT(0xA55701F5, 0xE3EF, 0x43DE, 0xAC, 0x72, 0x24, 0x9B, \ + 0x57, 0x3F, 0xAD, 0x2C) +#define INFO_ERR_STRUCT_TYPE_TLB \ + GUID_INIT(0xFC06B535, 0x5E1F, 0x4562, 0x9F, 0x25, 0x0A, 0x3B, \ + 0x9A, 0xDB, 0x63, 0xC3) +#define INFO_ERR_STRUCT_TYPE_BUS \ + GUID_INIT(0x1CF3F8B3, 0xC5B1, 0x49a2, 0xAA, 0x59, 0x5E, 0xEF, \ + 0x92, 0xFF, 0xA6, 0x3C) +#define INFO_ERR_STRUCT_TYPE_MS \ + GUID_INIT(0x48AB7F57, 0xDC34, 0x4f6c, 0xA7, 0xD3, 0xB0, 0xB5, \ + 0xB0, 0xA7, 0x43, 0x14) + +#define INFO_VALID_CHECK_INFO BIT_ULL(0) +#define INFO_VALID_TARGET_ID BIT_ULL(1) +#define INFO_VALID_REQUESTOR_ID BIT_ULL(2) +#define INFO_VALID_RESPONDER_ID BIT_ULL(3) +#define INFO_VALID_IP BIT_ULL(4) + +#define CHECK_VALID_TRANS_TYPE BIT_ULL(0) +#define CHECK_VALID_OPERATION BIT_ULL(1) +#define CHECK_VALID_LEVEL BIT_ULL(2) +#define CHECK_VALID_PCC BIT_ULL(3) +#define CHECK_VALID_UNCORRECTED BIT_ULL(4) +#define CHECK_VALID_PRECISE_IP BIT_ULL(5) +#define CHECK_VALID_RESTARTABLE_IP BIT_ULL(6) +#define CHECK_VALID_OVERFLOW BIT_ULL(7) + +#define CHECK_VALID_BUS_PART_TYPE BIT_ULL(8) +#define CHECK_VALID_BUS_TIME_OUT BIT_ULL(9) +#define CHECK_VALID_BUS_ADDR_SPACE BIT_ULL(10) + +#define CHECK_VALID_BITS(check) (((check) & GENMASK_ULL(15, 0))) +#define CHECK_TRANS_TYPE(check) (((check) & GENMASK_ULL(17, 16)) >> 16) +#define CHECK_OPERATION(check) (((check) & GENMASK_ULL(21, 18)) >> 18) +#define CHECK_LEVEL(check) (((check) & GENMASK_ULL(24, 22)) >> 22) +#define CHECK_PCC BIT_ULL(25) +#define CHECK_UNCORRECTED BIT_ULL(26) +#define CHECK_PRECISE_IP BIT_ULL(27) +#define CHECK_RESTARTABLE_IP BIT_ULL(28) +#define CHECK_OVERFLOW BIT_ULL(29) + +#define CHECK_BUS_PART_TYPE(check) (((check) & GENMASK_ULL(31, 30)) >> 30) +#define CHECK_BUS_TIME_OUT BIT_ULL(32) +#define CHECK_BUS_ADDR_SPACE(check) (((check) & GENMASK_ULL(34, 33)) >> 33) + +#define CHECK_VALID_MS_ERR_TYPE BIT_ULL(0) +#define CHECK_VALID_MS_PCC BIT_ULL(1) +#define CHECK_VALID_MS_UNCORRECTED BIT_ULL(2) +#define CHECK_VALID_MS_PRECISE_IP BIT_ULL(3) +#define CHECK_VALID_MS_RESTARTABLE_IP BIT_ULL(4) +#define CHECK_VALID_MS_OVERFLOW BIT_ULL(5) + +#define CHECK_MS_ERR_TYPE(check) (((check) & GENMASK_ULL(18, 16)) >> 16) +#define CHECK_MS_PCC BIT_ULL(19) +#define CHECK_MS_UNCORRECTED BIT_ULL(20) +#define CHECK_MS_PRECISE_IP BIT_ULL(21) +#define CHECK_MS_RESTARTABLE_IP BIT_ULL(22) +#define CHECK_MS_OVERFLOW BIT_ULL(23) + +#define CTX_TYPE_MSR 1 +#define CTX_TYPE_MMREG 7 + +enum err_types { + ERR_TYPE_CACHE = 0, + ERR_TYPE_TLB, + ERR_TYPE_BUS, + ERR_TYPE_MS, + N_ERR_TYPES +}; + +static enum err_types cper_get_err_type(const guid_t *err_type) +{ + if (guid_equal(err_type, &INFO_ERR_STRUCT_TYPE_CACHE)) + return ERR_TYPE_CACHE; + else if (guid_equal(err_type, &INFO_ERR_STRUCT_TYPE_TLB)) + return ERR_TYPE_TLB; + else if (guid_equal(err_type, &INFO_ERR_STRUCT_TYPE_BUS)) + return ERR_TYPE_BUS; + else if (guid_equal(err_type, &INFO_ERR_STRUCT_TYPE_MS)) + return ERR_TYPE_MS; + else + return N_ERR_TYPES; +} + +static const char * const ia_check_trans_type_strs[] = { + "Instruction", + "Data Access", + "Generic", +}; + +static const char * const ia_check_op_strs[] = { + "generic error", + "generic read", + "generic write", + "data read", + "data write", + "instruction fetch", + "prefetch", + "eviction", + "snoop", +}; + +static const char * const ia_check_bus_part_type_strs[] = { + "Local Processor originated request", + "Local Processor responded to request", + "Local Processor observed", + "Generic", +}; + +static const char * const ia_check_bus_addr_space_strs[] = { + "Memory Access", + "Reserved", + "I/O", + "Other Transaction", +}; + +static const char * const ia_check_ms_error_type_strs[] = { + "No Error", + "Unclassified", + "Microcode ROM Parity Error", + "External Error", + "FRC Error", + "Internal Unclassified", +}; + +static const char * const ia_reg_ctx_strs[] = { + "Unclassified Data", + "MSR Registers (Machine Check and other MSRs)", + "32-bit Mode Execution Context", + "64-bit Mode Execution Context", + "FXSAVE Context", + "32-bit Mode Debug Registers (DR0-DR7)", + "64-bit Mode Debug Registers (DR0-DR7)", + "Memory Mapped Registers", +}; + +static inline void print_bool(char *str, const char *pfx, u64 check, u64 bit) +{ + printk("%s%s: %s\n", pfx, str, (check & bit) ? "true" : "false"); +} + +static void print_err_info_ms(const char *pfx, u16 validation_bits, u64 check) +{ + if (validation_bits & CHECK_VALID_MS_ERR_TYPE) { + u8 err_type = CHECK_MS_ERR_TYPE(check); + + printk("%sError Type: %u, %s\n", pfx, err_type, + err_type < ARRAY_SIZE(ia_check_ms_error_type_strs) ? + ia_check_ms_error_type_strs[err_type] : "unknown"); + } + + if (validation_bits & CHECK_VALID_MS_PCC) + print_bool("Processor Context Corrupt", pfx, check, CHECK_MS_PCC); + + if (validation_bits & CHECK_VALID_MS_UNCORRECTED) + print_bool("Uncorrected", pfx, check, CHECK_MS_UNCORRECTED); + + if (validation_bits & CHECK_VALID_MS_PRECISE_IP) + print_bool("Precise IP", pfx, check, CHECK_MS_PRECISE_IP); + + if (validation_bits & CHECK_VALID_MS_RESTARTABLE_IP) + print_bool("Restartable IP", pfx, check, CHECK_MS_RESTARTABLE_IP); + + if (validation_bits & CHECK_VALID_MS_OVERFLOW) + print_bool("Overflow", pfx, check, CHECK_MS_OVERFLOW); +} + +static void print_err_info(const char *pfx, u8 err_type, u64 check) +{ + u16 validation_bits = CHECK_VALID_BITS(check); + + /* + * The MS Check structure varies a lot from the others, so use a + * separate function for decoding. + */ + if (err_type == ERR_TYPE_MS) + return print_err_info_ms(pfx, validation_bits, check); + + if (validation_bits & CHECK_VALID_TRANS_TYPE) { + u8 trans_type = CHECK_TRANS_TYPE(check); + + printk("%sTransaction Type: %u, %s\n", pfx, trans_type, + trans_type < ARRAY_SIZE(ia_check_trans_type_strs) ? + ia_check_trans_type_strs[trans_type] : "unknown"); + } + + if (validation_bits & CHECK_VALID_OPERATION) { + u8 op = CHECK_OPERATION(check); + + /* + * CACHE has more operation types than TLB or BUS, though the + * name and the order are the same. + */ + u8 max_ops = (err_type == ERR_TYPE_CACHE) ? 9 : 7; + + printk("%sOperation: %u, %s\n", pfx, op, + op < max_ops ? ia_check_op_strs[op] : "unknown"); + } + + if (validation_bits & CHECK_VALID_LEVEL) + printk("%sLevel: %llu\n", pfx, CHECK_LEVEL(check)); + + if (validation_bits & CHECK_VALID_PCC) + print_bool("Processor Context Corrupt", pfx, check, CHECK_PCC); + + if (validation_bits & CHECK_VALID_UNCORRECTED) + print_bool("Uncorrected", pfx, check, CHECK_UNCORRECTED); + + if (validation_bits & CHECK_VALID_PRECISE_IP) + print_bool("Precise IP", pfx, check, CHECK_PRECISE_IP); + + if (validation_bits & CHECK_VALID_RESTARTABLE_IP) + print_bool("Restartable IP", pfx, check, CHECK_RESTARTABLE_IP); + + if (validation_bits & CHECK_VALID_OVERFLOW) + print_bool("Overflow", pfx, check, CHECK_OVERFLOW); + + if (err_type != ERR_TYPE_BUS) + return; + + if (validation_bits & CHECK_VALID_BUS_PART_TYPE) { + u8 part_type = CHECK_BUS_PART_TYPE(check); + + printk("%sParticipation Type: %u, %s\n", pfx, part_type, + part_type < ARRAY_SIZE(ia_check_bus_part_type_strs) ? + ia_check_bus_part_type_strs[part_type] : "unknown"); + } + + if (validation_bits & CHECK_VALID_BUS_TIME_OUT) + print_bool("Time Out", pfx, check, CHECK_BUS_TIME_OUT); + + if (validation_bits & CHECK_VALID_BUS_ADDR_SPACE) { + u8 addr_space = CHECK_BUS_ADDR_SPACE(check); + + printk("%sAddress Space: %u, %s\n", pfx, addr_space, + addr_space < ARRAY_SIZE(ia_check_bus_addr_space_strs) ? + ia_check_bus_addr_space_strs[addr_space] : "unknown"); + } +} + +void cper_print_proc_ia(const char *pfx, const struct cper_sec_proc_ia *proc) +{ + int i; + struct cper_ia_err_info *err_info; + struct cper_ia_proc_ctx *ctx_info; + char newpfx[64], infopfx[64]; + u8 err_type; + + if (proc->validation_bits & VALID_LAPIC_ID) + printk("%sLocal APIC_ID: 0x%llx\n", pfx, proc->lapic_id); + + if (proc->validation_bits & VALID_CPUID_INFO) { + printk("%sCPUID Info:\n", pfx); + print_hex_dump(pfx, "", DUMP_PREFIX_OFFSET, 16, 4, proc->cpuid, + sizeof(proc->cpuid), 0); + } + + snprintf(newpfx, sizeof(newpfx), "%s ", pfx); + + err_info = (struct cper_ia_err_info *)(proc + 1); + for (i = 0; i < VALID_PROC_ERR_INFO_NUM(proc->validation_bits); i++) { + printk("%sError Information Structure %d:\n", pfx, i); + + err_type = cper_get_err_type(&err_info->err_type); + printk("%sError Structure Type: %s\n", newpfx, + err_type < ARRAY_SIZE(cper_proc_error_type_strs) ? + cper_proc_error_type_strs[err_type] : "unknown"); + + if (err_type >= N_ERR_TYPES) { + printk("%sError Structure Type: %pUl\n", newpfx, + &err_info->err_type); + } + + if (err_info->validation_bits & INFO_VALID_CHECK_INFO) { + printk("%sCheck Information: 0x%016llx\n", newpfx, + err_info->check_info); + + if (err_type < N_ERR_TYPES) { + snprintf(infopfx, sizeof(infopfx), "%s ", + newpfx); + + print_err_info(infopfx, err_type, + err_info->check_info); + } + } + + if (err_info->validation_bits & INFO_VALID_TARGET_ID) { + printk("%sTarget Identifier: 0x%016llx\n", + newpfx, err_info->target_id); + } + + if (err_info->validation_bits & INFO_VALID_REQUESTOR_ID) { + printk("%sRequestor Identifier: 0x%016llx\n", + newpfx, err_info->requestor_id); + } + + if (err_info->validation_bits & INFO_VALID_RESPONDER_ID) { + printk("%sResponder Identifier: 0x%016llx\n", + newpfx, err_info->responder_id); + } + + if (err_info->validation_bits & INFO_VALID_IP) { + printk("%sInstruction Pointer: 0x%016llx\n", + newpfx, err_info->ip); + } + + err_info++; + } + + ctx_info = (struct cper_ia_proc_ctx *)err_info; + for (i = 0; i < VALID_PROC_CXT_INFO_NUM(proc->validation_bits); i++) { + int size = sizeof(*ctx_info) + ctx_info->reg_arr_size; + int groupsize = 4; + + printk("%sContext Information Structure %d:\n", pfx, i); + + printk("%sRegister Context Type: %s\n", newpfx, + ctx_info->reg_ctx_type < ARRAY_SIZE(ia_reg_ctx_strs) ? + ia_reg_ctx_strs[ctx_info->reg_ctx_type] : "unknown"); + + printk("%sRegister Array Size: 0x%04x\n", newpfx, + ctx_info->reg_arr_size); + + if (ctx_info->reg_ctx_type == CTX_TYPE_MSR) { + groupsize = 8; /* MSRs are 8 bytes wide. */ + printk("%sMSR Address: 0x%08x\n", newpfx, + ctx_info->msr_addr); + } + + if (ctx_info->reg_ctx_type == CTX_TYPE_MMREG) { + printk("%sMM Register Address: 0x%016llx\n", newpfx, + ctx_info->mm_reg_addr); + } + + printk("%sRegister Array:\n", newpfx); + print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, groupsize, + (ctx_info + 1), ctx_info->reg_arr_size, 0); + + ctx_info = (struct cper_ia_proc_ctx *)((long)ctx_info + size); + } +} diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c index c165933ebf38..3bf0dca378a6 100644 --- a/drivers/firmware/efi/cper.c +++ b/drivers/firmware/efi/cper.c @@ -37,8 +37,6 @@ #include <acpi/ghes.h> #include <ras/ras_event.h> -#define INDENT_SP " " - static char rcd_decode_str[CPER_REC_LEN]; /* @@ -433,7 +431,7 @@ cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT) printk("%s""fru_text: %.20s\n", pfx, gdata->fru_text); - snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP); + snprintf(newpfx, sizeof(newpfx), "%s ", pfx); if (guid_equal(sec_type, &CPER_SEC_PROC_GENERIC)) { struct cper_sec_proc_generic *proc_err = acpi_hest_get_payload(gdata); @@ -470,6 +468,16 @@ cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata else goto err_section_too_small; #endif +#if defined(CONFIG_UEFI_CPER_X86) + } else if (guid_equal(sec_type, &CPER_SEC_PROC_IA)) { + struct cper_sec_proc_ia *ia_err = acpi_hest_get_payload(gdata); + + printk("%ssection_type: IA32/X64 processor error\n", newpfx); + if (gdata->error_data_length >= sizeof(*ia_err)) + cper_print_proc_ia(newpfx, ia_err); + else + goto err_section_too_small; +#endif } else { const void *err = acpi_hest_get_payload(gdata); @@ -500,7 +508,7 @@ void cper_estatus_print(const char *pfx, "It has been corrected by h/w " "and requires no further action"); printk("%s""event severity: %s\n", pfx, cper_severity_str(severity)); - snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP); + snprintf(newpfx, sizeof(newpfx), "%s ", pfx); apei_estatus_for_each_section(estatus, gdata) { cper_estatus_print_section(newpfx, gdata, sec_no); diff --git a/drivers/firmware/efi/libstub/secureboot.c b/drivers/firmware/efi/libstub/secureboot.c index 8f07eb414c00..72d9dfbebf08 100644 --- a/drivers/firmware/efi/libstub/secureboot.c +++ b/drivers/firmware/efi/libstub/secureboot.c @@ -30,6 +30,9 @@ static const efi_char16_t shim_MokSBState_name[] = L"MokSBState"; /* * Determine whether we're in secure boot mode. + * + * Please keep the logic in sync with + * arch/x86/xen/efi.c:xen_efi_get_secureboot(). */ enum efi_secureboot_mode efi_get_secureboot(efi_system_table_t *sys_table_arg) { diff --git a/drivers/firmware/efi/libstub/tpm.c b/drivers/firmware/efi/libstub/tpm.c index 9d08cea3f1b0..caa37a6dd9d4 100644 --- a/drivers/firmware/efi/libstub/tpm.c +++ b/drivers/firmware/efi/libstub/tpm.c @@ -59,7 +59,7 @@ void efi_enable_reset_attack_mitigation(efi_system_table_t *sys_table_arg) #endif -void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg) +static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg) { efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID; efi_guid_t linux_eventlog_guid = LINUX_EFI_TPM_EVENT_LOG_GUID; diff --git a/drivers/firmware/qcom_scm-32.c b/drivers/firmware/qcom_scm-32.c index dfbd894d5bb7..4e24e591ae74 100644 --- a/drivers/firmware/qcom_scm-32.c +++ b/drivers/firmware/qcom_scm-32.c @@ -147,7 +147,7 @@ static u32 smc(u32 cmd_addr) "smc #0 @ switch to secure world\n" : "=r" (r0) : "r" (r0), "r" (r1), "r" (r2) - : "r3"); + : "r3", "r12"); } while (r0 == QCOM_SCM_INTERRUPTED); return r0; @@ -263,7 +263,7 @@ static s32 qcom_scm_call_atomic1(u32 svc, u32 cmd, u32 arg1) "smc #0 @ switch to secure world\n" : "=r" (r0) : "r" (r0), "r" (r1), "r" (r2) - : "r3"); + : "r3", "r12"); return r0; } @@ -298,7 +298,7 @@ static s32 qcom_scm_call_atomic2(u32 svc, u32 cmd, u32 arg1, u32 arg2) "smc #0 @ switch to secure world\n" : "=r" (r0) : "r" (r0), "r" (r1), "r" (r2), "r" (r3) - ); + : "r12"); return r0; } @@ -328,7 +328,7 @@ u32 qcom_scm_get_version(void) "smc #0 @ switch to secure world\n" : "=r" (r0), "=r" (r1) : "r" (r0), "r" (r1) - : "r2", "r3"); + : "r2", "r3", "r12"); } while (r0 == QCOM_SCM_INTERRUPTED); version = r1; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c index a29362f9ef41..12558044acd4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c @@ -513,7 +513,7 @@ static int acp_hw_fini(void *handle) if (adev->acp.acp_genpd) { for (i = 0; i < ACP_DEVS ; i++) { dev = get_mfd_cell_dev(adev->acp.acp_cell[i].name, i); - ret = pm_genpd_remove_device(&adev->acp.acp_genpd->gpd, dev); + ret = pm_genpd_remove_device(dev); /* If removal fails, dont giveup and try rest */ if (ret) dev_err(dev, "remove dev from genpd failed\n"); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 1dd1142246c2..27579443cdc5 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -4555,8 +4555,8 @@ static int dm_update_crtcs_state(struct dc *dc, for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { struct amdgpu_crtc *acrtc = NULL; struct amdgpu_dm_connector *aconnector = NULL; - struct drm_connector_state *new_con_state = NULL; - struct dm_connector_state *dm_conn_state = NULL; + struct drm_connector_state *drm_new_conn_state = NULL, *drm_old_conn_state = NULL; + struct dm_connector_state *dm_new_conn_state = NULL, *dm_old_conn_state = NULL; struct drm_plane_state *new_plane_state = NULL; new_stream = NULL; @@ -4577,19 +4577,23 @@ static int dm_update_crtcs_state(struct dc *dc, /* TODO This hack should go away */ if (aconnector && enable) { // Make sure fake sink is created in plug-in scenario - new_con_state = drm_atomic_get_connector_state(state, + drm_new_conn_state = drm_atomic_get_new_connector_state(state, &aconnector->base); + drm_old_conn_state = drm_atomic_get_old_connector_state(state, + &aconnector->base); - if (IS_ERR(new_con_state)) { - ret = PTR_ERR_OR_ZERO(new_con_state); + + if (IS_ERR(drm_new_conn_state)) { + ret = PTR_ERR_OR_ZERO(drm_new_conn_state); break; } - dm_conn_state = to_dm_connector_state(new_con_state); + dm_new_conn_state = to_dm_connector_state(drm_new_conn_state); + dm_old_conn_state = to_dm_connector_state(drm_old_conn_state); new_stream = create_stream_for_sink(aconnector, &new_crtc_state->mode, - dm_conn_state); + dm_new_conn_state); /* * we can have no stream on ACTION_SET if a display @@ -4695,20 +4699,30 @@ next_crtc: * We want to do dc stream updates that do not require a * full modeset below. */ - if (!enable || !aconnector || modereset_required(new_crtc_state)) + if (!(enable && aconnector && new_crtc_state->enable && + new_crtc_state->active)) continue; /* * Given above conditions, the dc state cannot be NULL because: - * 1. We're attempting to enable a CRTC. Which has a... - * 2. Valid connector attached, and - * 3. User does not want to reset it (disable or mark inactive, - * which can happen on a CRTC that's already disabled). - * => It currently exists. + * 1. We're in the process of enabling CRTCs (just been added + * to the dc context, or already is on the context) + * 2. Has a valid connector attached, and + * 3. Is currently active and enabled. + * => The dc stream state currently exists. */ BUG_ON(dm_new_crtc_state->stream == NULL); - /* Color managment settings */ - if (dm_new_crtc_state->base.color_mgmt_changed) { + /* Scaling or underscan settings */ + if (is_scaling_state_different(dm_old_conn_state, dm_new_conn_state)) + update_stream_scaling_settings( + &new_crtc_state->mode, dm_new_conn_state, dm_new_crtc_state->stream); + + /* + * Color management settings. We also update color properties + * when a modeset is needed, to ensure it gets reprogrammed. + */ + if (dm_new_crtc_state->base.color_mgmt_changed || + drm_atomic_crtc_needs_modeset(new_crtc_state)) { ret = amdgpu_dm_set_regamma_lut(dm_new_crtc_state); if (ret) goto fail; diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index ec8d0006ef7c..3c136f2b954f 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -2077,7 +2077,7 @@ static irqreturn_t dw_hdmi_hardirq(int irq, void *dev_id) return ret; } -void __dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense) +void dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense) { mutex_lock(&hdmi->mutex); @@ -2103,13 +2103,6 @@ void __dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense) } mutex_unlock(&hdmi->mutex); } - -void dw_hdmi_setup_rx_sense(struct device *dev, bool hpd, bool rx_sense) -{ - struct dw_hdmi *hdmi = dev_get_drvdata(dev); - - __dw_hdmi_setup_rx_sense(hdmi, hpd, rx_sense); -} EXPORT_SYMBOL_GPL(dw_hdmi_setup_rx_sense); static irqreturn_t dw_hdmi_irq(int irq, void *dev_id) @@ -2145,9 +2138,9 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id) */ if (intr_stat & (HDMI_IH_PHY_STAT0_RX_SENSE | HDMI_IH_PHY_STAT0_HPD)) { - __dw_hdmi_setup_rx_sense(hdmi, - phy_stat & HDMI_PHY_HPD, - phy_stat & HDMI_PHY_RX_SENSE); + dw_hdmi_setup_rx_sense(hdmi, + phy_stat & HDMI_PHY_HPD, + phy_stat & HDMI_PHY_RX_SENSE); if ((phy_stat & (HDMI_PHY_RX_SENSE | HDMI_PHY_HPD)) == 0) cec_notifier_set_phys_addr(hdmi->cec_notifier, diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index ffe14ec3e7f2..70ae1f232331 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -1145,6 +1145,7 @@ int drm_dp_psr_setup_time(const u8 psr_cap[EDP_PSR_RECEIVER_CAP_SIZE]) static const u16 psr_setup_time_us[] = { PSR_SETUP_TIME(330), PSR_SETUP_TIME(275), + PSR_SETUP_TIME(220), PSR_SETUP_TIME(165), PSR_SETUP_TIME(110), PSR_SETUP_TIME(55), diff --git a/drivers/gpu/drm/i915/i915_query.c b/drivers/gpu/drm/i915/i915_query.c index 3ace929dd90f..3f502eef2431 100644 --- a/drivers/gpu/drm/i915/i915_query.c +++ b/drivers/gpu/drm/i915/i915_query.c @@ -4,6 +4,8 @@ * Copyright © 2018 Intel Corporation */ +#include <linux/nospec.h> + #include "i915_drv.h" #include "i915_query.h" #include <uapi/drm/i915_drm.h> @@ -100,7 +102,7 @@ int i915_query_ioctl(struct drm_device *dev, void *data, struct drm_file *file) for (i = 0; i < args->num_items; i++, user_item_ptr++) { struct drm_i915_query_item item; - u64 func_idx; + unsigned long func_idx; int ret; if (copy_from_user(&item, user_item_ptr, sizeof(item))) @@ -109,12 +111,17 @@ int i915_query_ioctl(struct drm_device *dev, void *data, struct drm_file *file) if (item.query_id == 0) return -EINVAL; + if (overflows_type(item.query_id - 1, unsigned long)) + return -EINVAL; + func_idx = item.query_id - 1; - if (func_idx < ARRAY_SIZE(i915_query_funcs)) + ret = -EINVAL; + if (func_idx < ARRAY_SIZE(i915_query_funcs)) { + func_idx = array_index_nospec(func_idx, + ARRAY_SIZE(i915_query_funcs)); ret = i915_query_funcs[func_idx](dev_priv, &item); - else - ret = -EINVAL; + } /* Only write the length back to userspace if they differ. */ if (ret != item.length && put_user(ret, &user_item_ptr->length)) diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 8691c86f579c..e125d16a1aa7 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -574,6 +574,36 @@ exit: return NOTIFY_OK; } +static int +intel_lvds_connector_register(struct drm_connector *connector) +{ + struct intel_lvds_connector *lvds = to_lvds_connector(connector); + int ret; + + ret = intel_connector_register(connector); + if (ret) + return ret; + + lvds->lid_notifier.notifier_call = intel_lid_notify; + if (acpi_lid_notifier_register(&lvds->lid_notifier)) { + DRM_DEBUG_KMS("lid notifier registration failed\n"); + lvds->lid_notifier.notifier_call = NULL; + } + + return 0; +} + +static void +intel_lvds_connector_unregister(struct drm_connector *connector) +{ + struct intel_lvds_connector *lvds = to_lvds_connector(connector); + + if (lvds->lid_notifier.notifier_call) + acpi_lid_notifier_unregister(&lvds->lid_notifier); + + intel_connector_unregister(connector); +} + /** * intel_lvds_destroy - unregister and free LVDS structures * @connector: connector to free @@ -586,9 +616,6 @@ static void intel_lvds_destroy(struct drm_connector *connector) struct intel_lvds_connector *lvds_connector = to_lvds_connector(connector); - if (lvds_connector->lid_notifier.notifier_call) - acpi_lid_notifier_unregister(&lvds_connector->lid_notifier); - if (!IS_ERR_OR_NULL(lvds_connector->base.edid)) kfree(lvds_connector->base.edid); @@ -609,8 +636,8 @@ static const struct drm_connector_funcs intel_lvds_connector_funcs = { .fill_modes = drm_helper_probe_single_connector_modes, .atomic_get_property = intel_digital_connector_atomic_get_property, .atomic_set_property = intel_digital_connector_atomic_set_property, - .late_register = intel_connector_register, - .early_unregister = intel_connector_unregister, + .late_register = intel_lvds_connector_register, + .early_unregister = intel_lvds_connector_unregister, .destroy = intel_lvds_destroy, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, .atomic_duplicate_state = intel_digital_connector_duplicate_state, @@ -827,6 +854,14 @@ static const struct dmi_system_id intel_no_lvds[] = { DMI_EXACT_MATCH(DMI_BOARD_NAME, "D525MW"), }, }, + { + .callback = intel_no_lvds_dmi_callback, + .ident = "Radiant P845", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Radiant Systems Inc"), + DMI_MATCH(DMI_PRODUCT_NAME, "P845"), + }, + }, { } /* terminating entry */ }; @@ -1150,12 +1185,6 @@ out: lvds_encoder->a3_power = lvds & LVDS_A3_POWER_MASK; - lvds_connector->lid_notifier.notifier_call = intel_lid_notify; - if (acpi_lid_notifier_register(&lvds_connector->lid_notifier)) { - DRM_DEBUG_KMS("lid notifier registration failed\n"); - lvds_connector->lid_notifier.notifier_call = NULL; - } - return; failed: diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c index a393095aac1a..c9ad45686e7a 100644 --- a/drivers/gpu/drm/meson/meson_dw_hdmi.c +++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c @@ -529,7 +529,7 @@ static irqreturn_t dw_hdmi_top_thread_irq(int irq, void *dev_id) if (stat & HDMITX_TOP_INTR_HPD_RISE) hpd_connected = true; - dw_hdmi_setup_rx_sense(dw_hdmi->dev, hpd_connected, + dw_hdmi_setup_rx_sense(dw_hdmi->hdmi, hpd_connected, hpd_connected); drm_helper_hpd_irq_event(dw_hdmi->encoder.dev); diff --git a/drivers/gpu/drm/omapdrm/dss/sdi.c b/drivers/gpu/drm/omapdrm/dss/sdi.c index 68a40ae26f5b..1e2c931f6acf 100644 --- a/drivers/gpu/drm/omapdrm/dss/sdi.c +++ b/drivers/gpu/drm/omapdrm/dss/sdi.c @@ -82,7 +82,7 @@ static int sdi_calc_clock_div(struct sdi_device *sdi, unsigned long pclk, struct dispc_clock_info *dispc_cinfo) { int i; - struct sdi_clk_calc_ctx ctx = { .sdi = sdi }; + struct sdi_clk_calc_ctx ctx; /* * DSS fclk gives us very few possibilities, so finding a good pixel @@ -95,6 +95,9 @@ static int sdi_calc_clock_div(struct sdi_device *sdi, unsigned long pclk, bool ok; memset(&ctx, 0, sizeof(ctx)); + + ctx.sdi = sdi; + if (pclk > 1000 * i * i * i) ctx.pck_min = max(pclk - 1000 * i * i * i, 0lu); else diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c index 3d2d3bbd1342..155ad840f3c5 100644 --- a/drivers/gpu/drm/rcar-du/rcar_lvds.c +++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c @@ -88,6 +88,9 @@ static int rcar_lvds_connector_atomic_check(struct drm_connector *connector, const struct drm_display_mode *panel_mode; struct drm_crtc_state *crtc_state; + if (!state->crtc) + return 0; + if (list_empty(&connector->modes)) { dev_dbg(lvds->dev, "connector: empty modes list\n"); return -EINVAL; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 70e1a8820a7c..8b770a8e02cd 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -1278,8 +1278,6 @@ static void vmw_master_drop(struct drm_device *dev, dev_priv->active_master = &dev_priv->fbdev_master; ttm_lock_set_kill(&dev_priv->fbdev_master.lock, false, SIGTERM); ttm_vt_unlock(&dev_priv->fbdev_master.lock); - - vmw_fb_refresh(dev_priv); } /** @@ -1483,7 +1481,6 @@ static int vmw_pm_freeze(struct device *kdev) vmw_kms_resume(dev); if (dev_priv->enable_fb) vmw_fb_on(dev_priv); - vmw_fb_refresh(dev_priv); return -EBUSY; } @@ -1523,8 +1520,6 @@ static int vmw_pm_restore(struct device *kdev) if (dev_priv->enable_fb) vmw_fb_on(dev_priv); - vmw_fb_refresh(dev_priv); - return 0; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index f34f368c1a2e..5fcbe1620d50 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -910,7 +910,6 @@ int vmw_fb_init(struct vmw_private *vmw_priv); int vmw_fb_close(struct vmw_private *dev_priv); int vmw_fb_off(struct vmw_private *vmw_priv); int vmw_fb_on(struct vmw_private *vmw_priv); -void vmw_fb_refresh(struct vmw_private *vmw_priv); /** * Kernel modesetting - vmwgfx_kms.c diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index ba0cdb743c3e..54e300365a5c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -866,21 +866,13 @@ int vmw_fb_on(struct vmw_private *vmw_priv) spin_lock_irqsave(&par->dirty.lock, flags); par->dirty.active = true; spin_unlock_irqrestore(&par->dirty.lock, flags); - - return 0; -} -/** - * vmw_fb_refresh - Refresh fb display - * - * @vmw_priv: Pointer to device private - * - * Call into kms to show the fbdev display(s). - */ -void vmw_fb_refresh(struct vmw_private *vmw_priv) -{ - if (!vmw_priv->fb_info) - return; + /* + * Need to reschedule a dirty update, because otherwise that's + * only done in dirty_mark() if the previous coalesced + * dirty region was empty. + */ + schedule_delayed_work(&par->local_work, 0); - vmw_fb_set_par(vmw_priv->fb_info); + return 0; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c index cdff99211602..21d746bdc922 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c @@ -329,8 +329,6 @@ int vmw_host_get_guestinfo(const char *guest_info_param, struct rpc_channel channel; char *msg, *reply = NULL; size_t reply_len = 0; - int ret = 0; - if (!vmw_msg_enabled) return -ENODEV; @@ -344,15 +342,14 @@ int vmw_host_get_guestinfo(const char *guest_info_param, return -ENOMEM; } - if (vmw_open_channel(&channel, RPCI_PROTOCOL_NUM) || - vmw_send_msg(&channel, msg) || - vmw_recv_msg(&channel, (void *) &reply, &reply_len) || - vmw_close_channel(&channel)) { - DRM_ERROR("Failed to get %s", guest_info_param); + if (vmw_open_channel(&channel, RPCI_PROTOCOL_NUM)) + goto out_open; - ret = -EINVAL; - } + if (vmw_send_msg(&channel, msg) || + vmw_recv_msg(&channel, (void *) &reply, &reply_len)) + goto out_msg; + vmw_close_channel(&channel); if (buffer && reply && reply_len > 0) { /* Remove reply code, which are the first 2 characters of * the reply @@ -369,7 +366,17 @@ int vmw_host_get_guestinfo(const char *guest_info_param, kfree(reply); kfree(msg); - return ret; + return 0; + +out_msg: + vmw_close_channel(&channel); + kfree(reply); +out_open: + *length = 0; + kfree(msg); + DRM_ERROR("Failed to get %s", guest_info_param); + + return -EINVAL; } @@ -400,15 +407,22 @@ int vmw_host_log(const char *log) return -ENOMEM; } - if (vmw_open_channel(&channel, RPCI_PROTOCOL_NUM) || - vmw_send_msg(&channel, msg) || - vmw_close_channel(&channel)) { - DRM_ERROR("Failed to send log\n"); + if (vmw_open_channel(&channel, RPCI_PROTOCOL_NUM)) + goto out_open; - ret = -EINVAL; - } + if (vmw_send_msg(&channel, msg)) + goto out_msg; + vmw_close_channel(&channel); kfree(msg); - return ret; + return 0; + +out_msg: + vmw_close_channel(&channel); +out_open: + kfree(msg); + DRM_ERROR("Failed to send log\n"); + + return -EINVAL; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.h b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.h index 557a033fb610..8545488aa0cf 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.h @@ -135,17 +135,24 @@ #else -/* In the 32-bit version of this macro, we use "m" because there is no - * more register left for bp +/* + * In the 32-bit version of this macro, we store bp in a memory location + * because we've ran out of registers. + * Now we can't reference that memory location while we've modified + * %esp or %ebp, so we first push it on the stack, just before we push + * %ebp, and then when we need it we read it from the stack where we + * just pushed it. */ #define VMW_PORT_HB_OUT(cmd, in_ecx, in_si, in_di, \ port_num, magic, bp, \ eax, ebx, ecx, edx, si, di) \ ({ \ - asm volatile ("push %%ebp;" \ - "mov %12, %%ebp;" \ + asm volatile ("push %12;" \ + "push %%ebp;" \ + "mov 0x04(%%esp), %%ebp;" \ "rep outsb;" \ - "pop %%ebp;" : \ + "pop %%ebp;" \ + "add $0x04, %%esp;" : \ "=a"(eax), \ "=b"(ebx), \ "=c"(ecx), \ @@ -167,10 +174,12 @@ port_num, magic, bp, \ eax, ebx, ecx, edx, si, di) \ ({ \ - asm volatile ("push %%ebp;" \ - "mov %12, %%ebp;" \ + asm volatile ("push %12;" \ + "push %%ebp;" \ + "mov 0x04(%%esp), %%ebp;" \ "rep insb;" \ - "pop %%ebp" : \ + "pop %%ebp;" \ + "add $0x04, %%esp;" : \ "=a"(eax), \ "=b"(ebx), \ "=c"(ecx), \ diff --git a/drivers/gpu/host1x/bus.c b/drivers/gpu/host1x/bus.c index 88a3558b7916..815bdb42e3f0 100644 --- a/drivers/gpu/host1x/bus.c +++ b/drivers/gpu/host1x/bus.c @@ -314,6 +314,11 @@ static int host1x_device_match(struct device *dev, struct device_driver *drv) return strcmp(dev_name(dev), drv->name) == 0; } +static int host1x_dma_configure(struct device *dev) +{ + return of_dma_configure(dev, dev->of_node, true); +} + static const struct dev_pm_ops host1x_device_pm_ops = { .suspend = pm_generic_suspend, .resume = pm_generic_resume, @@ -326,8 +331,8 @@ static const struct dev_pm_ops host1x_device_pm_ops = { struct bus_type host1x_bus_type = { .name = "host1x", .match = host1x_device_match, + .dma_configure = host1x_dma_configure, .pm = &host1x_device_pm_ops, - .force_dma = true, }; static void __host1x_device_del(struct host1x_device *device) @@ -416,7 +421,7 @@ static int host1x_device_add(struct host1x *host1x, device->dev.bus = &host1x_bus_type; device->dev.parent = host1x->dev; - of_dma_configure(&device->dev, host1x->dev->of_node); + of_dma_configure(&device->dev, host1x->dev->of_node, true); err = host1x_device_parse_dt(device, driver); if (err < 0) { diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 6ec307c93ece..f10840ad465c 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -717,15 +717,12 @@ config SENSORS_LTC2945 be called ltc2945. config SENSORS_LTC2990 - tristate "Linear Technology LTC2990 (current monitoring mode only)" + tristate "Linear Technology LTC2990" depends on I2C help If you say yes here you get support for Linear Technology LTC2990 I2C System Monitor. The LTC2990 supports a combination of voltage, - current and temperature monitoring, but in addition to the Vcc supply - voltage and chip temperature, this driver currently only supports - reading two currents by measuring two differential voltages across - series resistors. + current and temperature monitoring. This driver can also be built as a module. If so, the module will be called ltc2990. diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c index 975c43d446f8..a6636fe42189 100644 --- a/drivers/hwmon/asus_atk0110.c +++ b/drivers/hwmon/asus_atk0110.c @@ -125,6 +125,8 @@ struct atk_data { int temperature_count; int fan_count; struct list_head sensor_list; + struct attribute_group attr_group; + const struct attribute_group *attr_groups[2]; struct { struct dentry *root; @@ -188,7 +190,6 @@ static int atk_add(struct acpi_device *device); static int atk_remove(struct acpi_device *device); static void atk_print_sensor(struct atk_data *data, union acpi_object *obj); static int atk_read_value(struct atk_sensor_data *sensor, u64 *value); -static void atk_free_sensors(struct atk_data *data); static struct acpi_driver atk_driver = { .name = ATK_HID, @@ -262,14 +263,6 @@ static ssize_t atk_limit2_show(struct device *dev, return sprintf(buf, "%lld\n", value); } -static ssize_t atk_name_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "atk0110\n"); -} -static struct device_attribute atk_name_attr = - __ATTR(name, 0444, atk_name_show, NULL); - static void atk_init_attribute(struct device_attribute *attr, char *name, sysfs_show_func show) { @@ -912,15 +905,13 @@ static int atk_add_sensor(struct atk_data *data, union acpi_object *obj) limit1 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT1); limit2 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT2); - sensor = kzalloc(sizeof(*sensor), GFP_KERNEL); + sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL); if (!sensor) return -ENOMEM; - sensor->acpi_name = kstrdup(name->string.pointer, GFP_KERNEL); - if (!sensor->acpi_name) { - err = -ENOMEM; - goto out; - } + sensor->acpi_name = devm_kstrdup(dev, name->string.pointer, GFP_KERNEL); + if (!sensor->acpi_name) + return -ENOMEM; INIT_LIST_HEAD(&sensor->list); sensor->type = type; @@ -961,9 +952,6 @@ static int atk_add_sensor(struct atk_data *data, union acpi_object *obj) (*num)++; return 1; -out: - kfree(sensor); - return err; } static int atk_enumerate_old_hwmon(struct atk_data *data) @@ -1004,8 +992,7 @@ static int atk_enumerate_old_hwmon(struct atk_data *data) dev_warn(dev, METHOD_OLD_ENUM_TMP ": ACPI exception: %s\n", acpi_format_exception(status)); - ret = -ENODEV; - goto cleanup; + return -ENODEV; } pack = buf.pointer; @@ -1026,8 +1013,7 @@ static int atk_enumerate_old_hwmon(struct atk_data *data) dev_warn(dev, METHOD_OLD_ENUM_FAN ": ACPI exception: %s\n", acpi_format_exception(status)); - ret = -ENODEV; - goto cleanup; + return -ENODEV; } pack = buf.pointer; @@ -1041,9 +1027,6 @@ static int atk_enumerate_old_hwmon(struct atk_data *data) ACPI_FREE(buf.pointer); return count; -cleanup: - atk_free_sensors(data); - return ret; } static int atk_ec_present(struct atk_data *data) @@ -1193,76 +1176,44 @@ static int atk_enumerate_new_hwmon(struct atk_data *data) return err; } -static int atk_create_files(struct atk_data *data) +static int atk_init_attribute_groups(struct atk_data *data) { + struct device *dev = &data->acpi_dev->dev; struct atk_sensor_data *s; - int err; + struct attribute **attrs; + int i = 0; + int len = (data->voltage_count + data->temperature_count + + data->fan_count) * 4 + 1; - list_for_each_entry(s, &data->sensor_list, list) { - err = device_create_file(data->hwmon_dev, &s->input_attr); - if (err) - return err; - err = device_create_file(data->hwmon_dev, &s->label_attr); - if (err) - return err; - err = device_create_file(data->hwmon_dev, &s->limit1_attr); - if (err) - return err; - err = device_create_file(data->hwmon_dev, &s->limit2_attr); - if (err) - return err; - } - - err = device_create_file(data->hwmon_dev, &atk_name_attr); - - return err; -} - -static void atk_remove_files(struct atk_data *data) -{ - struct atk_sensor_data *s; + attrs = devm_kcalloc(dev, len, sizeof(struct attribute *), GFP_KERNEL); + if (!attrs) + return -ENOMEM; list_for_each_entry(s, &data->sensor_list, list) { - device_remove_file(data->hwmon_dev, &s->input_attr); - device_remove_file(data->hwmon_dev, &s->label_attr); - device_remove_file(data->hwmon_dev, &s->limit1_attr); - device_remove_file(data->hwmon_dev, &s->limit2_attr); + attrs[i++] = &s->input_attr.attr; + attrs[i++] = &s->label_attr.attr; + attrs[i++] = &s->limit1_attr.attr; + attrs[i++] = &s->limit2_attr.attr; } - device_remove_file(data->hwmon_dev, &atk_name_attr); -} -static void atk_free_sensors(struct atk_data *data) -{ - struct list_head *head = &data->sensor_list; - struct atk_sensor_data *s, *tmp; + data->attr_group.attrs = attrs; + data->attr_groups[0] = &data->attr_group; - list_for_each_entry_safe(s, tmp, head, list) { - kfree(s->acpi_name); - kfree(s); - } + return 0; } static int atk_register_hwmon(struct atk_data *data) { struct device *dev = &data->acpi_dev->dev; - int err; dev_dbg(dev, "registering hwmon device\n"); - data->hwmon_dev = hwmon_device_register(dev); + data->hwmon_dev = hwmon_device_register_with_groups(dev, "atk0110", + data, + data->attr_groups); if (IS_ERR(data->hwmon_dev)) return PTR_ERR(data->hwmon_dev); - dev_dbg(dev, "populating sysfs directory\n"); - err = atk_create_files(data); - if (err) - goto remove; - return 0; -remove: - /* Cleanup the registered files */ - atk_remove_files(data); - hwmon_device_unregister(data->hwmon_dev); - return err; } static int atk_probe_if(struct atk_data *data) @@ -1350,7 +1301,7 @@ static int atk_add(struct acpi_device *device) dev_dbg(&device->dev, "adding...\n"); - data = kzalloc(sizeof(*data), GFP_KERNEL); + data = devm_kzalloc(&device->dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; @@ -1397,20 +1348,20 @@ static int atk_add(struct acpi_device *device) goto out; } + err = atk_init_attribute_groups(data); + if (err) + goto out; err = atk_register_hwmon(data); if (err) - goto cleanup; + goto out; atk_debugfs_init(data); device->driver_data = data; return 0; -cleanup: - atk_free_sensors(data); out: if (data->disable_ec) atk_ec_ctl(data, 0); - kfree(data); return err; } @@ -1423,8 +1374,6 @@ static int atk_remove(struct acpi_device *device) atk_debugfs_cleanup(data); - atk_remove_files(data); - atk_free_sensors(data); hwmon_device_unregister(data->hwmon_dev); if (data->disable_ec) { @@ -1432,8 +1381,6 @@ static int atk_remove(struct acpi_device *device) dev_err(&device->dev, "Failed to disable EC\n"); } - kfree(data); - return 0; } diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c index 5e78229ade04..22d3a84f13ef 100644 --- a/drivers/hwmon/fschmd.c +++ b/drivers/hwmon/fschmd.c @@ -105,7 +105,7 @@ static const u8 FSCHMD_REG_VOLT[7][6] = { static const int FSCHMD_NO_VOLT_SENSORS[7] = { 3, 3, 3, 3, 3, 3, 6 }; /* - * minimum pwm at which the fan is driven (pwm can by increased depending on + * minimum pwm at which the fan is driven (pwm can be increased depending on * the temp. Notice that for the scy some fans share there minimum speed. * Also notice that with the scy the sensor order is different than with the * other chips, this order was in the 2.4 driver and kept for consistency. diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index 32083e452cde..e88c01961948 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -698,6 +698,9 @@ hwmon_device_register_with_info(struct device *dev, const char *name, if (chip && (!chip->ops || !chip->ops->is_visible || !chip->info)) return ERR_PTR(-EINVAL); + if (chip && !dev) + return ERR_PTR(-EINVAL); + return __hwmon_device_register(dev, name, drvdata, chip, extra_groups); } EXPORT_SYMBOL_GPL(hwmon_device_register_with_info); diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c index 3b73dee6fdc6..17c6460ae351 100644 --- a/drivers/hwmon/k10temp.c +++ b/drivers/hwmon/k10temp.c @@ -37,6 +37,10 @@ MODULE_PARM_DESC(force, "force loading on processors with erratum 319"); /* Provide lock for writing to NB_SMU_IND_ADDR */ static DEFINE_MUTEX(nb_smu_ind_mutex); +#ifndef PCI_DEVICE_ID_AMD_15H_M70H_NB_F3 +#define PCI_DEVICE_ID_AMD_15H_M70H_NB_F3 0x15b3 +#endif + #ifndef PCI_DEVICE_ID_AMD_17H_DF_F3 #define PCI_DEVICE_ID_AMD_17H_DF_F3 0x1463 #endif @@ -81,6 +85,7 @@ struct k10temp_data { void (*read_tempreg)(struct pci_dev *pdev, u32 *regval); int temp_offset; u32 temp_adjust_mask; + bool show_tdie; }; struct tctl_offset { @@ -141,17 +146,24 @@ static void read_tempreg_nb_f17(struct pci_dev *pdev, u32 *regval) F17H_M01H_REPORTED_TEMP_CTRL_OFFSET, regval); } -static ssize_t temp1_input_show(struct device *dev, - struct device_attribute *attr, char *buf) +static unsigned int get_raw_temp(struct k10temp_data *data) { - struct k10temp_data *data = dev_get_drvdata(dev); - u32 regval; unsigned int temp; + u32 regval; data->read_tempreg(data->pdev, ®val); temp = (regval >> 21) * 125; if (regval & data->temp_adjust_mask) temp -= 49000; + return temp; +} + +static ssize_t temp1_input_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct k10temp_data *data = dev_get_drvdata(dev); + unsigned int temp = get_raw_temp(data); + if (temp > data->temp_offset) temp -= data->temp_offset; else @@ -160,6 +172,23 @@ static ssize_t temp1_input_show(struct device *dev, return sprintf(buf, "%u\n", temp); } +static ssize_t temp2_input_show(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct k10temp_data *data = dev_get_drvdata(dev); + unsigned int temp = get_raw_temp(data); + + return sprintf(buf, "%u\n", temp); +} + +static ssize_t temp_label_show(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + + return sprintf(buf, "%s\n", attr->index ? "Tctl" : "Tdie"); +} + static ssize_t temp1_max_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -187,16 +216,23 @@ static DEVICE_ATTR_RO(temp1_max); static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit, NULL, 0); static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO, show_temp_crit, NULL, 1); +static SENSOR_DEVICE_ATTR(temp1_label, 0444, temp_label_show, NULL, 0); +static DEVICE_ATTR_RO(temp2_input); +static SENSOR_DEVICE_ATTR(temp2_label, 0444, temp_label_show, NULL, 1); + static umode_t k10temp_is_visible(struct kobject *kobj, struct attribute *attr, int index) { struct device *dev = container_of(kobj, struct device, kobj); struct k10temp_data *data = dev_get_drvdata(dev); struct pci_dev *pdev = data->pdev; + u32 reg; - if (index >= 2) { - u32 reg; - + switch (index) { + case 0 ... 1: /* temp1_input, temp1_max */ + default: + break; + case 2 ... 3: /* temp1_crit, temp1_crit_hyst */ if (!data->read_htcreg) return 0; @@ -208,6 +244,11 @@ static umode_t k10temp_is_visible(struct kobject *kobj, data->read_htcreg(data->pdev, ®); if (!(reg & HTC_ENABLE)) return 0; + break; + case 4 ... 6: /* temp1_label, temp2_input, temp2_label */ + if (!data->show_tdie) + return 0; + break; } return attr->mode; } @@ -217,6 +258,9 @@ static struct attribute *k10temp_attrs[] = { &dev_attr_temp1_max.attr, &sensor_dev_attr_temp1_crit.dev_attr.attr, &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_label.dev_attr.attr, + &dev_attr_temp2_input.attr, + &sensor_dev_attr_temp2_label.dev_attr.attr, NULL }; @@ -292,6 +336,7 @@ static int k10temp_probe(struct pci_dev *pdev, } else if (boot_cpu_data.x86 == 0x17) { data->temp_adjust_mask = 0x80000; data->read_tempreg = read_tempreg_nb_f17; + data->show_tdie = true; } else { data->read_htcreg = read_htcreg_pci; data->read_tempreg = read_tempreg_pci; @@ -320,6 +365,7 @@ static const struct pci_device_id k10temp_id_table[] = { { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M10H_F3) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F3) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M60H_NB_F3) }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M70H_NB_F3) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_NB_F3) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F3) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_DF_F3) }, diff --git a/drivers/hwmon/ltc2990.c b/drivers/hwmon/ltc2990.c index 8f8fe059ab48..2aefdc58b242 100644 --- a/drivers/hwmon/ltc2990.c +++ b/drivers/hwmon/ltc2990.c @@ -5,18 +5,16 @@ * Author: Mike Looijmans <mike.looijmans@topic.nl> * * License: GPLv2 - * - * This driver assumes the chip is wired as a dual current monitor, and - * reports the voltage drop across two series resistors. It also reports - * the chip's internal temperature and Vcc power supply voltage. */ +#include <linux/bitops.h> #include <linux/err.h> #include <linux/hwmon.h> #include <linux/hwmon-sysfs.h> #include <linux/i2c.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/of.h> #define LTC2990_STATUS 0x00 #define LTC2990_CONTROL 0x01 @@ -28,45 +26,108 @@ #define LTC2990_V4_MSB 0x0C #define LTC2990_VCC_MSB 0x0E -#define LTC2990_CONTROL_KELVIN BIT(7) -#define LTC2990_CONTROL_SINGLE BIT(6) -#define LTC2990_CONTROL_MEASURE_ALL (0x3 << 3) -#define LTC2990_CONTROL_MODE_CURRENT 0x06 -#define LTC2990_CONTROL_MODE_VOLTAGE 0x07 +#define LTC2990_IN0 BIT(0) +#define LTC2990_IN1 BIT(1) +#define LTC2990_IN2 BIT(2) +#define LTC2990_IN3 BIT(3) +#define LTC2990_IN4 BIT(4) +#define LTC2990_CURR1 BIT(5) +#define LTC2990_CURR2 BIT(6) +#define LTC2990_TEMP1 BIT(7) +#define LTC2990_TEMP2 BIT(8) +#define LTC2990_TEMP3 BIT(9) +#define LTC2990_NONE 0 +#define LTC2990_ALL GENMASK(9, 0) -/* convert raw register value to sign-extended integer in 16-bit range */ -static int ltc2990_voltage_to_int(int raw) -{ - if (raw & BIT(14)) - return -(0x4000 - (raw & 0x3FFF)) << 2; - else - return (raw & 0x3FFF) << 2; -} +#define LTC2990_MODE0_SHIFT 0 +#define LTC2990_MODE0_MASK GENMASK(2, 0) +#define LTC2990_MODE1_SHIFT 3 +#define LTC2990_MODE1_MASK GENMASK(1, 0) + +/* Enabled measurements for mode bits 2..0 */ +static const int ltc2990_attrs_ena_0[] = { + LTC2990_IN1 | LTC2990_IN2 | LTC2990_TEMP3, + LTC2990_CURR1 | LTC2990_TEMP3, + LTC2990_CURR1 | LTC2990_IN3 | LTC2990_IN4, + LTC2990_TEMP2 | LTC2990_IN3 | LTC2990_IN4, + LTC2990_TEMP2 | LTC2990_CURR2, + LTC2990_TEMP2 | LTC2990_TEMP3, + LTC2990_CURR1 | LTC2990_CURR2, + LTC2990_IN1 | LTC2990_IN2 | LTC2990_IN3 | LTC2990_IN4 +}; + +/* Enabled measurements for mode bits 4..3 */ +static const int ltc2990_attrs_ena_1[] = { + LTC2990_NONE, + LTC2990_TEMP2 | LTC2990_IN1 | LTC2990_CURR1, + LTC2990_TEMP3 | LTC2990_IN3 | LTC2990_CURR2, + LTC2990_ALL +}; + +struct ltc2990_data { + struct i2c_client *i2c; + u32 mode[2]; +}; /* Return the converted value from the given register in uV or mC */ -static int ltc2990_get_value(struct i2c_client *i2c, u8 reg, int *result) +static int ltc2990_get_value(struct i2c_client *i2c, int index, int *result) { int val; + u8 reg; + + switch (index) { + case LTC2990_IN0: + reg = LTC2990_VCC_MSB; + break; + case LTC2990_IN1: + case LTC2990_CURR1: + case LTC2990_TEMP2: + reg = LTC2990_V1_MSB; + break; + case LTC2990_IN2: + reg = LTC2990_V2_MSB; + break; + case LTC2990_IN3: + case LTC2990_CURR2: + case LTC2990_TEMP3: + reg = LTC2990_V3_MSB; + break; + case LTC2990_IN4: + reg = LTC2990_V4_MSB; + break; + case LTC2990_TEMP1: + reg = LTC2990_TINT_MSB; + break; + default: + return -EINVAL; + } val = i2c_smbus_read_word_swapped(i2c, reg); if (unlikely(val < 0)) return val; - switch (reg) { - case LTC2990_TINT_MSB: - /* internal temp, 0.0625 degrees/LSB, 13-bit */ - val = (val & 0x1FFF) << 3; - *result = (val * 1000) >> 7; + switch (index) { + case LTC2990_TEMP1: + case LTC2990_TEMP2: + case LTC2990_TEMP3: + /* temp, 0.0625 degrees/LSB */ + *result = sign_extend32(val, 12) * 1000 / 16; break; - case LTC2990_V1_MSB: - case LTC2990_V3_MSB: - /* Vx-Vy, 19.42uV/LSB. Depends on mode. */ - *result = ltc2990_voltage_to_int(val) * 1942 / (4 * 100); + case LTC2990_CURR1: + case LTC2990_CURR2: + /* Vx-Vy, 19.42uV/LSB */ + *result = sign_extend32(val, 14) * 1942 / 100; break; - case LTC2990_VCC_MSB: - /* Vcc, 305.18μV/LSB, 2.5V offset */ - *result = (ltc2990_voltage_to_int(val) * 30518 / - (4 * 100 * 1000)) + 2500; + case LTC2990_IN0: + /* Vcc, 305.18uV/LSB, 2.5V offset */ + *result = sign_extend32(val, 14) * 30518 / (100 * 1000) + 2500; + break; + case LTC2990_IN1: + case LTC2990_IN2: + case LTC2990_IN3: + case LTC2990_IN4: + /* Vx, 305.18uV/LSB */ + *result = sign_extend32(val, 14) * 30518 / (100 * 1000); break; default: return -EINVAL; /* won't happen, keep compiler happy */ @@ -79,48 +140,117 @@ static ssize_t ltc2990_show_value(struct device *dev, struct device_attribute *da, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct ltc2990_data *data = dev_get_drvdata(dev); int value; int ret; - ret = ltc2990_get_value(dev_get_drvdata(dev), attr->index, &value); + ret = ltc2990_get_value(data->i2c, attr->index, &value); if (unlikely(ret < 0)) return ret; return snprintf(buf, PAGE_SIZE, "%d\n", value); } +static umode_t ltc2990_attrs_visible(struct kobject *kobj, + struct attribute *a, int n) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct ltc2990_data *data = dev_get_drvdata(dev); + struct device_attribute *da = + container_of(a, struct device_attribute, attr); + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + + int attrs_mask = LTC2990_IN0 | LTC2990_TEMP1 | + (ltc2990_attrs_ena_0[data->mode[0]] & + ltc2990_attrs_ena_1[data->mode[1]]); + + if (attr->index & attrs_mask) + return a->mode; + + return 0; +} + static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, ltc2990_show_value, NULL, - LTC2990_TINT_MSB); + LTC2990_TEMP1); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, ltc2990_show_value, NULL, + LTC2990_TEMP2); +static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, ltc2990_show_value, NULL, + LTC2990_TEMP3); static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc2990_show_value, NULL, - LTC2990_V1_MSB); + LTC2990_CURR1); static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO, ltc2990_show_value, NULL, - LTC2990_V3_MSB); + LTC2990_CURR2); static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ltc2990_show_value, NULL, - LTC2990_VCC_MSB); + LTC2990_IN0); +static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc2990_show_value, NULL, + LTC2990_IN1); +static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc2990_show_value, NULL, + LTC2990_IN2); +static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, ltc2990_show_value, NULL, + LTC2990_IN3); +static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, ltc2990_show_value, NULL, + LTC2990_IN4); static struct attribute *ltc2990_attrs[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp3_input.dev_attr.attr, &sensor_dev_attr_curr1_input.dev_attr.attr, &sensor_dev_attr_curr2_input.dev_attr.attr, &sensor_dev_attr_in0_input.dev_attr.attr, + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_in4_input.dev_attr.attr, NULL, }; -ATTRIBUTE_GROUPS(ltc2990); + +static const struct attribute_group ltc2990_group = { + .attrs = ltc2990_attrs, + .is_visible = ltc2990_attrs_visible, +}; +__ATTRIBUTE_GROUPS(ltc2990); static int ltc2990_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { int ret; struct device *hwmon_dev; + struct ltc2990_data *data; + struct device_node *of_node = i2c->dev.of_node; if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) return -ENODEV; - /* Setup continuous mode, current monitor */ + data = devm_kzalloc(&i2c->dev, sizeof(struct ltc2990_data), GFP_KERNEL); + if (unlikely(!data)) + return -ENOMEM; + + data->i2c = i2c; + + if (of_node) { + ret = of_property_read_u32_array(of_node, "lltc,meas-mode", + data->mode, 2); + if (ret < 0) + return ret; + + if (data->mode[0] & ~LTC2990_MODE0_MASK || + data->mode[1] & ~LTC2990_MODE1_MASK) + return -EINVAL; + } else { + ret = i2c_smbus_read_byte_data(i2c, LTC2990_CONTROL); + if (ret < 0) + return ret; + + data->mode[0] = ret >> LTC2990_MODE0_SHIFT & LTC2990_MODE0_MASK; + data->mode[1] = ret >> LTC2990_MODE1_SHIFT & LTC2990_MODE1_MASK; + } + + /* Setup continuous mode */ ret = i2c_smbus_write_byte_data(i2c, LTC2990_CONTROL, - LTC2990_CONTROL_MEASURE_ALL | - LTC2990_CONTROL_MODE_CURRENT); + data->mode[0] << LTC2990_MODE0_SHIFT | + data->mode[1] << LTC2990_MODE1_SHIFT); if (ret < 0) { dev_err(&i2c->dev, "Error: Failed to set control mode.\n"); return ret; @@ -134,7 +264,7 @@ static int ltc2990_i2c_probe(struct i2c_client *i2c, hwmon_dev = devm_hwmon_device_register_with_groups(&i2c->dev, i2c->name, - i2c, + data, ltc2990_groups); return PTR_ERR_OR_ZERO(hwmon_dev); diff --git a/drivers/hwmon/mc13783-adc.c b/drivers/hwmon/mc13783-adc.c index 960a1db6f269..67860ad2e3d9 100644 --- a/drivers/hwmon/mc13783-adc.c +++ b/drivers/hwmon/mc13783-adc.c @@ -63,6 +63,10 @@ static int mc13783_adc_read(struct device *dev, if (ret) return ret; + /* ADIN7 subchannels */ + if (channel >= 16) + channel = 7; + channel &= 0x7; *val = (sample[channel % 4] >> (channel > 3 ? 14 : 2)) & 0x3ff; @@ -111,6 +115,57 @@ static ssize_t mc13783_adc_read_gp(struct device *dev, return sprintf(buf, "%u\n", val); } +static ssize_t mc13783_adc_read_uid(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + unsigned int val; + struct platform_device *pdev = to_platform_device(dev); + kernel_ulong_t driver_data = platform_get_device_id(pdev)->driver_data; + int ret = mc13783_adc_read(dev, devattr, &val); + + if (ret) + return ret; + + if (driver_data & MC13783_ADC_BPDIV2) + /* MC13892 have 1/2 divider, input range is [0, 4.800V] */ + val = DIV_ROUND_CLOSEST(val * 4800, 1024); + else + /* MC13783 have 0.9 divider, input range is [0, 2.555V] */ + val = DIV_ROUND_CLOSEST(val * 2555, 1024); + + return sprintf(buf, "%u\n", val); +} + +static ssize_t mc13783_adc_read_temp(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + unsigned int val; + struct platform_device *pdev = to_platform_device(dev); + kernel_ulong_t driver_data = platform_get_device_id(pdev)->driver_data; + int ret = mc13783_adc_read(dev, devattr, &val); + + if (ret) + return ret; + + if (driver_data & MC13783_ADC_BPDIV2) { + /* + * MC13892: + * Die Temperature Read Out Code at 25C 680 + * Temperature change per LSB +0.4244C + */ + ret = DIV_ROUND_CLOSEST(-2635920 + val * 4244, 10); + } else { + /* + * MC13783: + * Die Temperature Read Out Code at 25C 282 + * Temperature change per LSB -1.14C + */ + ret = 346480 - 1140 * val; + } + + return sprintf(buf, "%d\n", ret); +} + static DEVICE_ATTR_RO(name); static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, mc13783_adc_read_bp, NULL, 2); static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, mc13783_adc_read_gp, NULL, 5); @@ -124,6 +179,9 @@ static SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, mc13783_adc_read_gp, NULL, 12); static SENSOR_DEVICE_ATTR(in13_input, S_IRUGO, mc13783_adc_read_gp, NULL, 13); static SENSOR_DEVICE_ATTR(in14_input, S_IRUGO, mc13783_adc_read_gp, NULL, 14); static SENSOR_DEVICE_ATTR(in15_input, S_IRUGO, mc13783_adc_read_gp, NULL, 15); +static SENSOR_DEVICE_ATTR(in16_input, S_IRUGO, mc13783_adc_read_uid, NULL, 16); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, + mc13783_adc_read_temp, NULL, 17); static struct attribute *mc13783_attr_base[] = { &dev_attr_name.attr, @@ -131,6 +189,8 @@ static struct attribute *mc13783_attr_base[] = { &sensor_dev_attr_in5_input.dev_attr.attr, &sensor_dev_attr_in6_input.dev_attr.attr, &sensor_dev_attr_in7_input.dev_attr.attr, + &sensor_dev_attr_in16_input.dev_attr.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, NULL }; diff --git a/drivers/hwtracing/intel_th/msu.c b/drivers/hwtracing/intel_th/msu.c index ede388309376..634f58042c77 100644 --- a/drivers/hwtracing/intel_th/msu.c +++ b/drivers/hwtracing/intel_th/msu.c @@ -733,8 +733,8 @@ err_nomem: /* Reset the page to write-back before releasing */ set_memory_wb((unsigned long)win->block[i].bdesc, 1); #endif - dma_free_coherent(msc_dev(msc), size, win->block[i].bdesc, - win->block[i].addr); + dma_free_coherent(msc_dev(msc)->parent->parent, size, + win->block[i].bdesc, win->block[i].addr); } kfree(win); @@ -769,7 +769,7 @@ static void msc_buffer_win_free(struct msc *msc, struct msc_window *win) /* Reset the page to write-back before releasing */ set_memory_wb((unsigned long)win->block[i].bdesc, 1); #endif - dma_free_coherent(msc_dev(win->msc), PAGE_SIZE, + dma_free_coherent(msc_dev(win->msc)->parent->parent, PAGE_SIZE, win->block[i].bdesc, win->block[i].addr); } diff --git a/drivers/hwtracing/stm/core.c b/drivers/hwtracing/stm/core.c index 05386b76465e..10bcb5d73f90 100644 --- a/drivers/hwtracing/stm/core.c +++ b/drivers/hwtracing/stm/core.c @@ -19,6 +19,7 @@ #include <linux/stm.h> #include <linux/fs.h> #include <linux/mm.h> +#include <linux/vmalloc.h> #include "stm.h" #include <uapi/linux/stm.h> @@ -674,7 +675,7 @@ static void stm_device_release(struct device *dev) { struct stm_device *stm = to_stm_device(dev); - kfree(stm); + vfree(stm); } int stm_register_device(struct device *parent, struct stm_data *stm_data, @@ -691,7 +692,7 @@ int stm_register_device(struct device *parent, struct stm_data *stm_data, return -EINVAL; nmasters = stm_data->sw_end - stm_data->sw_start + 1; - stm = kzalloc(sizeof(*stm) + nmasters * sizeof(void *), GFP_KERNEL); + stm = vzalloc(sizeof(*stm) + nmasters * sizeof(void *)); if (!stm) return -ENOMEM; @@ -744,7 +745,7 @@ err_device: /* matches device_initialize() above */ put_device(&stm->dev); err_free: - kfree(stm); + vfree(stm); return err; } diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index 8c42ca7107b2..45ae3c025bf6 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -1,6 +1,6 @@ /* * i2c-ocores.c: I2C bus driver for OpenCores I2C controller - * (http://www.opencores.org/projects.cgi/web/i2c/overview). + * (https://opencores.org/project/i2c/overview) * * Peter Korsgaard <jacmet@sunsite.dk> * diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index 1ba40bb2b966..a17f46a95f73 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -363,7 +363,7 @@ static int i2c_device_probe(struct device *dev) goto err_clear_wakeup_irq; status = dev_pm_domain_attach(&client->dev, true); - if (status == -EPROBE_DEFER) + if (status) goto err_clear_wakeup_irq; /* diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c index 0e6bc631a1ca..8b2b72b93885 100644 --- a/drivers/ide/ide-atapi.c +++ b/drivers/ide/ide-atapi.c @@ -92,7 +92,7 @@ int ide_queue_pc_tail(ide_drive_t *drive, struct gendisk *disk, struct request *rq; int error; - rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, __GFP_RECLAIM); + rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0); ide_req(rq)->type = ATA_PRIV_MISC; rq->special = (char *)pc; diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 5a8e8e3c22cd..5f178384876f 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -437,7 +437,7 @@ int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd, bool delay = false; rq = blk_get_request(drive->queue, - write ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN, __GFP_RECLAIM); + write ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN, 0); memcpy(scsi_req(rq)->cmd, cmd, BLK_MAX_CDB); ide_req(rq)->type = ATA_PRIV_PC; rq->rq_flags |= rq_flags; @@ -1426,21 +1426,8 @@ static int idecd_capacity_proc_show(struct seq_file *m, void *v) return 0; } -static int idecd_capacity_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, idecd_capacity_proc_show, PDE_DATA(inode)); -} - -static const struct file_operations idecd_capacity_proc_fops = { - .owner = THIS_MODULE, - .open = idecd_capacity_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static ide_proc_entry_t idecd_proc[] = { - { "capacity", S_IFREG|S_IRUGO, &idecd_capacity_proc_fops }, + { "capacity", S_IFREG|S_IRUGO, idecd_capacity_proc_show }, {} }; diff --git a/drivers/ide/ide-cd_ioctl.c b/drivers/ide/ide-cd_ioctl.c index 2acca12b9c94..b1322400887b 100644 --- a/drivers/ide/ide-cd_ioctl.c +++ b/drivers/ide/ide-cd_ioctl.c @@ -304,7 +304,7 @@ int ide_cdrom_reset(struct cdrom_device_info *cdi) struct request *rq; int ret; - rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, __GFP_RECLAIM); + rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0); ide_req(rq)->type = ATA_PRIV_MISC; rq->rq_flags = RQF_QUIET; blk_execute_rq(drive->queue, cd->disk, rq, 0); diff --git a/drivers/ide/ide-devsets.c b/drivers/ide/ide-devsets.c index 4e20747af32e..f4f8afdf8bbe 100644 --- a/drivers/ide/ide-devsets.c +++ b/drivers/ide/ide-devsets.c @@ -166,7 +166,7 @@ int ide_devset_execute(ide_drive_t *drive, const struct ide_devset *setting, if (!(setting->flags & DS_SYNC)) return setting->set(drive, arg); - rq = blk_get_request(q, REQ_OP_DRV_IN, __GFP_RECLAIM); + rq = blk_get_request(q, REQ_OP_DRV_IN, 0); ide_req(rq)->type = ATA_PRIV_MISC; scsi_req(rq)->cmd_len = 5; scsi_req(rq)->cmd[0] = REQ_DEVSET_EXEC; diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index f1a7c58fe418..e3b4e659082d 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -478,7 +478,7 @@ static int set_multcount(ide_drive_t *drive, int arg) if (drive->special_flags & IDE_SFLAG_SET_MULTMODE) return -EBUSY; - rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, __GFP_RECLAIM); + rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0); ide_req(rq)->type = ATA_PRIV_TASKFILE; drive->mult_req = arg; diff --git a/drivers/ide/ide-disk_proc.c b/drivers/ide/ide-disk_proc.c index 82a36ced4e96..95d239b2f646 100644 --- a/drivers/ide/ide-disk_proc.c +++ b/drivers/ide/ide-disk_proc.c @@ -52,19 +52,6 @@ static int idedisk_cache_proc_show(struct seq_file *m, void *v) return 0; } -static int idedisk_cache_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, idedisk_cache_proc_show, PDE_DATA(inode)); -} - -static const struct file_operations idedisk_cache_proc_fops = { - .owner = THIS_MODULE, - .open = idedisk_cache_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static int idedisk_capacity_proc_show(struct seq_file *m, void *v) { ide_drive_t*drive = (ide_drive_t *)m->private; @@ -73,19 +60,6 @@ static int idedisk_capacity_proc_show(struct seq_file *m, void *v) return 0; } -static int idedisk_capacity_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, idedisk_capacity_proc_show, PDE_DATA(inode)); -} - -static const struct file_operations idedisk_capacity_proc_fops = { - .owner = THIS_MODULE, - .open = idedisk_capacity_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static int __idedisk_proc_show(struct seq_file *m, ide_drive_t *drive, u8 sub_cmd) { u8 *buf; @@ -114,43 +88,17 @@ static int idedisk_sv_proc_show(struct seq_file *m, void *v) return __idedisk_proc_show(m, m->private, ATA_SMART_READ_VALUES); } -static int idedisk_sv_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, idedisk_sv_proc_show, PDE_DATA(inode)); -} - -static const struct file_operations idedisk_sv_proc_fops = { - .owner = THIS_MODULE, - .open = idedisk_sv_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static int idedisk_st_proc_show(struct seq_file *m, void *v) { return __idedisk_proc_show(m, m->private, ATA_SMART_READ_THRESHOLDS); } -static int idedisk_st_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, idedisk_st_proc_show, PDE_DATA(inode)); -} - -static const struct file_operations idedisk_st_proc_fops = { - .owner = THIS_MODULE, - .open = idedisk_st_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - ide_proc_entry_t ide_disk_proc[] = { - { "cache", S_IFREG|S_IRUGO, &idedisk_cache_proc_fops }, - { "capacity", S_IFREG|S_IRUGO, &idedisk_capacity_proc_fops }, - { "geometry", S_IFREG|S_IRUGO, &ide_geometry_proc_fops }, - { "smart_values", S_IFREG|S_IRUSR, &idedisk_sv_proc_fops }, - { "smart_thresholds", S_IFREG|S_IRUSR, &idedisk_st_proc_fops }, + { "cache", S_IFREG|S_IRUGO, idedisk_cache_proc_show }, + { "capacity", S_IFREG|S_IRUGO, idedisk_capacity_proc_show }, + { "geometry", S_IFREG|S_IRUGO, ide_geometry_proc_show }, + { "smart_values", S_IFREG|S_IRUSR, idedisk_sv_proc_show }, + { "smart_thresholds", S_IFREG|S_IRUSR, idedisk_st_proc_show }, {} }; diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index 54d4d78ca46a..6f344654ef22 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -180,7 +180,6 @@ EXPORT_SYMBOL_GPL(ide_dma_unmap_sg); void ide_dma_off_quietly(ide_drive_t *drive) { drive->dev_flags &= ~IDE_DFLAG_USING_DMA; - ide_toggle_bounce(drive, 0); drive->hwif->dma_ops->dma_host_set(drive, 0); } @@ -211,7 +210,6 @@ EXPORT_SYMBOL(ide_dma_off); void ide_dma_on(ide_drive_t *drive) { drive->dev_flags |= IDE_DFLAG_USING_DMA; - ide_toggle_bounce(drive, 1); drive->hwif->dma_ops->dma_host_set(drive, 1); } diff --git a/drivers/ide/ide-floppy_proc.c b/drivers/ide/ide-floppy_proc.c index 471457ebea67..7f697ddb5fe5 100644 --- a/drivers/ide/ide-floppy_proc.c +++ b/drivers/ide/ide-floppy_proc.c @@ -14,22 +14,9 @@ static int idefloppy_capacity_proc_show(struct seq_file *m, void *v) return 0; } -static int idefloppy_capacity_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, idefloppy_capacity_proc_show, PDE_DATA(inode)); -} - -static const struct file_operations idefloppy_capacity_proc_fops = { - .owner = THIS_MODULE, - .open = idefloppy_capacity_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - ide_proc_entry_t ide_floppy_proc[] = { - { "capacity", S_IFREG|S_IRUGO, &idefloppy_capacity_proc_fops }, - { "geometry", S_IFREG|S_IRUGO, &ide_geometry_proc_fops }, + { "capacity", S_IFREG|S_IRUGO, idefloppy_capacity_proc_show }, + { "geometry", S_IFREG|S_IRUGO, ide_geometry_proc_show }, {} }; diff --git a/drivers/ide/ide-ioctls.c b/drivers/ide/ide-ioctls.c index 3661abb16a5f..af5119a73689 100644 --- a/drivers/ide/ide-ioctls.c +++ b/drivers/ide/ide-ioctls.c @@ -125,7 +125,7 @@ static int ide_cmd_ioctl(ide_drive_t *drive, unsigned long arg) if (NULL == (void *) arg) { struct request *rq; - rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, __GFP_RECLAIM); + rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0); ide_req(rq)->type = ATA_PRIV_TASKFILE; blk_execute_rq(drive->queue, NULL, rq, 0); err = scsi_req(rq)->result ? -EIO : 0; @@ -222,7 +222,7 @@ static int generic_drive_reset(ide_drive_t *drive) struct request *rq; int ret = 0; - rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, __GFP_RECLAIM); + rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0); ide_req(rq)->type = ATA_PRIV_MISC; scsi_req(rq)->cmd_len = 1; scsi_req(rq)->cmd[0] = REQ_DRIVE_RESET; diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c index e1180fa46196..78cb79eddc8b 100644 --- a/drivers/ide/ide-lib.c +++ b/drivers/ide/ide-lib.c @@ -6,32 +6,6 @@ #include <linux/ide.h> #include <linux/bitops.h> -/** - * ide_toggle_bounce - handle bounce buffering - * @drive: drive to update - * @on: on/off boolean - * - * Enable or disable bounce buffering for the device. Drives move - * between PIO and DMA and that changes the rules we need. - */ - -void ide_toggle_bounce(ide_drive_t *drive, int on) -{ - u64 addr = BLK_BOUNCE_HIGH; /* dma64_addr_t */ - - if (!PCI_DMA_BUS_IS_PHYS) { - addr = BLK_BOUNCE_ANY; - } else if (on && drive->media == ide_disk) { - struct device *dev = drive->hwif->dev; - - if (dev && dev->dma_mask) - addr = *dev->dma_mask; - } - - if (drive->queue) - blk_queue_bounce_limit(drive->queue, addr); -} - u64 ide_get_lba_addr(struct ide_cmd *cmd, int lba48) { struct ide_taskfile *tf = &cmd->tf; diff --git a/drivers/ide/ide-park.c b/drivers/ide/ide-park.c index 6465bcc7cea6..622f0edb3945 100644 --- a/drivers/ide/ide-park.c +++ b/drivers/ide/ide-park.c @@ -32,7 +32,7 @@ static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout) } spin_unlock_irq(&hwif->lock); - rq = blk_get_request(q, REQ_OP_DRV_IN, __GFP_RECLAIM); + rq = blk_get_request(q, REQ_OP_DRV_IN, 0); scsi_req(rq)->cmd[0] = REQ_PARK_HEADS; scsi_req(rq)->cmd_len = 1; ide_req(rq)->type = ATA_PRIV_MISC; @@ -47,7 +47,7 @@ static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout) * Make sure that *some* command is sent to the drive after the * timeout has expired, so power management will be reenabled. */ - rq = blk_get_request(q, REQ_OP_DRV_IN, GFP_NOWAIT); + rq = blk_get_request(q, REQ_OP_DRV_IN, BLK_MQ_REQ_NOWAIT); if (IS_ERR(rq)) goto out; diff --git a/drivers/ide/ide-pm.c b/drivers/ide/ide-pm.c index ad8a125defdd..59217aa1d1fb 100644 --- a/drivers/ide/ide-pm.c +++ b/drivers/ide/ide-pm.c @@ -19,7 +19,7 @@ int generic_ide_suspend(struct device *dev, pm_message_t mesg) } memset(&rqpm, 0, sizeof(rqpm)); - rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, __GFP_RECLAIM); + rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0); ide_req(rq)->type = ATA_PRIV_PM_SUSPEND; rq->special = &rqpm; rqpm.pm_step = IDE_PM_START_SUSPEND; @@ -90,8 +90,7 @@ int generic_ide_resume(struct device *dev) } memset(&rqpm, 0, sizeof(rqpm)); - rq = blk_get_request_flags(drive->queue, REQ_OP_DRV_IN, - BLK_MQ_REQ_PREEMPT); + rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, BLK_MQ_REQ_PREEMPT); ide_req(rq)->type = ATA_PRIV_PM_RESUME; rq->special = &rqpm; rqpm.pm_step = IDE_PM_START_RESUME; diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 2019e66eada7..56d7bc228cb3 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -796,8 +796,7 @@ static int ide_init_queue(ide_drive_t *drive) * This will be fixed once we teach pci_map_sg() about our boundary * requirements, hopefully soon. *FIXME* */ - if (!PCI_DMA_BUS_IS_PHYS) - max_sg_entries >>= 1; + max_sg_entries >>= 1; #endif /* CONFIG_PCI */ blk_queue_max_segments(q, max_sg_entries); @@ -805,9 +804,6 @@ static int ide_init_queue(ide_drive_t *drive) /* assign drive queue */ drive->queue = q; - /* needs drive->queue to be set */ - ide_toggle_bounce(drive, 1); - return 0; } diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c index 863db44c7916..45c997430332 100644 --- a/drivers/ide/ide-proc.c +++ b/drivers/ide/ide-proc.c @@ -56,19 +56,6 @@ static int ide_imodel_proc_show(struct seq_file *m, void *v) return 0; } -static int ide_imodel_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, ide_imodel_proc_show, PDE_DATA(inode)); -} - -static const struct file_operations ide_imodel_proc_fops = { - .owner = THIS_MODULE, - .open = ide_imodel_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static int ide_mate_proc_show(struct seq_file *m, void *v) { ide_hwif_t *hwif = (ide_hwif_t *) m->private; @@ -80,19 +67,6 @@ static int ide_mate_proc_show(struct seq_file *m, void *v) return 0; } -static int ide_mate_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, ide_mate_proc_show, PDE_DATA(inode)); -} - -static const struct file_operations ide_mate_proc_fops = { - .owner = THIS_MODULE, - .open = ide_mate_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static int ide_channel_proc_show(struct seq_file *m, void *v) { ide_hwif_t *hwif = (ide_hwif_t *) m->private; @@ -101,19 +75,6 @@ static int ide_channel_proc_show(struct seq_file *m, void *v) return 0; } -static int ide_channel_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, ide_channel_proc_show, PDE_DATA(inode)); -} - -static const struct file_operations ide_channel_proc_fops = { - .owner = THIS_MODULE, - .open = ide_channel_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static int ide_identify_proc_show(struct seq_file *m, void *v) { ide_drive_t *drive = (ide_drive_t *)m->private; @@ -141,19 +102,6 @@ static int ide_identify_proc_show(struct seq_file *m, void *v) return 0; } -static int ide_identify_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, ide_identify_proc_show, PDE_DATA(inode)); -} - -static const struct file_operations ide_identify_proc_fops = { - .owner = THIS_MODULE, - .open = ide_identify_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - /** * ide_find_setting - find a specific setting * @st: setting table pointer @@ -441,27 +389,14 @@ static const struct file_operations ide_settings_proc_fops = { .write = ide_settings_proc_write, }; -static int ide_capacity_proc_show(struct seq_file *m, void *v) +int ide_capacity_proc_show(struct seq_file *m, void *v) { seq_printf(m, "%llu\n", (long long)0x7fffffff); return 0; } +EXPORT_SYMBOL_GPL(ide_capacity_proc_show); -static int ide_capacity_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, ide_capacity_proc_show, NULL); -} - -const struct file_operations ide_capacity_proc_fops = { - .owner = THIS_MODULE, - .open = ide_capacity_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; -EXPORT_SYMBOL_GPL(ide_capacity_proc_fops); - -static int ide_geometry_proc_show(struct seq_file *m, void *v) +int ide_geometry_proc_show(struct seq_file *m, void *v) { ide_drive_t *drive = (ide_drive_t *) m->private; @@ -471,20 +406,7 @@ static int ide_geometry_proc_show(struct seq_file *m, void *v) drive->bios_cyl, drive->bios_head, drive->bios_sect); return 0; } - -static int ide_geometry_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, ide_geometry_proc_show, PDE_DATA(inode)); -} - -const struct file_operations ide_geometry_proc_fops = { - .owner = THIS_MODULE, - .open = ide_geometry_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; -EXPORT_SYMBOL(ide_geometry_proc_fops); +EXPORT_SYMBOL(ide_geometry_proc_show); static int ide_dmodel_proc_show(struct seq_file *seq, void *v) { @@ -495,19 +417,6 @@ static int ide_dmodel_proc_show(struct seq_file *seq, void *v) return 0; } -static int ide_dmodel_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, ide_dmodel_proc_show, PDE_DATA(inode)); -} - -static const struct file_operations ide_dmodel_proc_fops = { - .owner = THIS_MODULE, - .open = ide_dmodel_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static int ide_driver_proc_show(struct seq_file *m, void *v) { ide_drive_t *drive = (ide_drive_t *)m->private; @@ -523,65 +432,6 @@ static int ide_driver_proc_show(struct seq_file *m, void *v) return 0; } -static int ide_driver_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, ide_driver_proc_show, PDE_DATA(inode)); -} - -static int ide_replace_subdriver(ide_drive_t *drive, const char *driver) -{ - struct device *dev = &drive->gendev; - int ret = 1; - int err; - - device_release_driver(dev); - /* FIXME: device can still be in use by previous driver */ - strlcpy(drive->driver_req, driver, sizeof(drive->driver_req)); - err = device_attach(dev); - if (err < 0) - printk(KERN_WARNING "IDE: %s: device_attach error: %d\n", - __func__, err); - drive->driver_req[0] = 0; - if (dev->driver == NULL) { - err = device_attach(dev); - if (err < 0) - printk(KERN_WARNING - "IDE: %s: device_attach(2) error: %d\n", - __func__, err); - } - if (dev->driver && !strcmp(dev->driver->name, driver)) - ret = 0; - - return ret; -} - -static ssize_t ide_driver_proc_write(struct file *file, const char __user *buffer, - size_t count, loff_t *pos) -{ - ide_drive_t *drive = PDE_DATA(file_inode(file)); - char name[32]; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - if (count > 31) - count = 31; - if (copy_from_user(name, buffer, count)) - return -EFAULT; - name[count] = '\0'; - if (ide_replace_subdriver(drive, name)) - return -EINVAL; - return count; -} - -static const struct file_operations ide_driver_proc_fops = { - .owner = THIS_MODULE, - .open = ide_driver_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .write = ide_driver_proc_write, -}; - static int ide_media_proc_show(struct seq_file *m, void *v) { ide_drive_t *drive = (ide_drive_t *) m->private; @@ -613,11 +463,10 @@ static const struct file_operations ide_media_proc_fops = { }; static ide_proc_entry_t generic_drive_entries[] = { - { "driver", S_IFREG|S_IRUGO, &ide_driver_proc_fops }, - { "identify", S_IFREG|S_IRUSR, &ide_identify_proc_fops}, - { "media", S_IFREG|S_IRUGO, &ide_media_proc_fops }, - { "model", S_IFREG|S_IRUGO, &ide_dmodel_proc_fops }, - { "settings", S_IFREG|S_IRUSR|S_IWUSR, &ide_settings_proc_fops}, + { "driver", S_IFREG|S_IRUGO, ide_driver_proc_show }, + { "identify", S_IFREG|S_IRUSR, ide_identify_proc_show }, + { "media", S_IFREG|S_IRUGO, ide_media_proc_show }, + { "model", S_IFREG|S_IRUGO, ide_dmodel_proc_show }, {} }; @@ -628,7 +477,7 @@ static void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p if (!dir || !p) return; while (p->name != NULL) { - ent = proc_create_data(p->name, p->mode, dir, p->proc_fops, data); + ent = proc_create_single_data(p->name, p->mode, dir, p->show, data); if (!ent) return; p++; } @@ -693,8 +542,12 @@ void ide_proc_port_register_devices(ide_hwif_t *hwif) continue; drive->proc = proc_mkdir(drive->name, parent); - if (drive->proc) + if (drive->proc) { ide_add_proc_entries(drive->proc, generic_drive_entries, drive); + proc_create_data("setting", S_IFREG|S_IRUSR|S_IWUSR, + drive->proc, &ide_settings_proc_fops, + drive); + } sprintf(name, "ide%d/%s", (drive->name[2]-'a')/2, drive->name); ent = proc_symlink(drive->name, proc_ide_root, name); if (!ent) return; @@ -704,6 +557,7 @@ void ide_proc_port_register_devices(ide_hwif_t *hwif) void ide_proc_unregister_device(ide_drive_t *drive) { if (drive->proc) { + remove_proc_entry("settings", drive->proc); ide_remove_proc_entries(drive->proc, generic_drive_entries); remove_proc_entry(drive->name, proc_ide_root); remove_proc_entry(drive->name, drive->hwif->proc); @@ -712,9 +566,9 @@ void ide_proc_unregister_device(ide_drive_t *drive) } static ide_proc_entry_t hwif_entries[] = { - { "channel", S_IFREG|S_IRUGO, &ide_channel_proc_fops }, - { "mate", S_IFREG|S_IRUGO, &ide_mate_proc_fops }, - { "model", S_IFREG|S_IRUGO, &ide_imodel_proc_fops }, + { "channel", S_IFREG|S_IRUGO, ide_channel_proc_show }, + { "mate", S_IFREG|S_IRUGO, ide_mate_proc_show }, + { "model", S_IFREG|S_IRUGO, ide_imodel_proc_show }, {} }; diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index fd57e8ccc47a..aee7b46d2330 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -854,7 +854,7 @@ static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int size) BUG_ON(cmd != REQ_IDETAPE_READ && cmd != REQ_IDETAPE_WRITE); BUG_ON(size < 0 || size % tape->blk_size); - rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, __GFP_RECLAIM); + rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0); ide_req(rq)->type = ATA_PRIV_MISC; scsi_req(rq)->cmd[13] = cmd; rq->rq_disk = tape->disk; @@ -862,7 +862,7 @@ static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int size) if (size) { ret = blk_rq_map_kern(drive->queue, rq, tape->buf, size, - __GFP_RECLAIM); + GFP_NOIO); if (ret) goto out_put; } @@ -1847,22 +1847,9 @@ static int idetape_name_proc_show(struct seq_file *m, void *v) return 0; } -static int idetape_name_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, idetape_name_proc_show, PDE_DATA(inode)); -} - -static const struct file_operations idetape_name_proc_fops = { - .owner = THIS_MODULE, - .open = idetape_name_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static ide_proc_entry_t idetape_proc[] = { - { "capacity", S_IFREG|S_IRUGO, &ide_capacity_proc_fops }, - { "name", S_IFREG|S_IRUGO, &idetape_name_proc_fops }, + { "capacity", S_IFREG|S_IRUGO, ide_capacity_proc_show }, + { "name", S_IFREG|S_IRUGO, idetape_name_proc_show }, {} }; diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c index abe0822dd429..c034cd965831 100644 --- a/drivers/ide/ide-taskfile.c +++ b/drivers/ide/ide-taskfile.c @@ -431,7 +431,7 @@ int ide_raw_taskfile(ide_drive_t *drive, struct ide_cmd *cmd, u8 *buf, rq = blk_get_request(drive->queue, (cmd->tf_flags & IDE_TFLAG_WRITE) ? - REQ_OP_DRV_OUT : REQ_OP_DRV_IN, __GFP_RECLAIM); + REQ_OP_DRV_OUT : REQ_OP_DRV_IN, 0); ide_req(rq)->type = ATA_PRIV_TASKFILE; /* @@ -442,7 +442,7 @@ int ide_raw_taskfile(ide_drive_t *drive, struct ide_cmd *cmd, u8 *buf, */ if (nsect) { error = blk_rq_map_kern(drive->queue, rq, buf, - nsect * SECTOR_SIZE, __GFP_RECLAIM); + nsect * SECTOR_SIZE, GFP_NOIO); if (error) goto put_req; } diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 15606f237480..9da79070357c 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -158,6 +158,7 @@ config AT91_SAMA5D2_ADC depends on ARCH_AT91 || COMPILE_TEST depends on HAS_IOMEM depends on HAS_DMA + select IIO_BUFFER select IIO_TRIGGERED_BUFFER help Say yes here to build support for Atmel SAMA5D2 ADC which is diff --git a/drivers/iio/adc/ad7793.c b/drivers/iio/adc/ad7793.c index 801afb61310b..d4bbe5b53318 100644 --- a/drivers/iio/adc/ad7793.c +++ b/drivers/iio/adc/ad7793.c @@ -348,55 +348,6 @@ static const u16 ad7793_sample_freq_avail[16] = {0, 470, 242, 123, 62, 50, 39, static const u16 ad7797_sample_freq_avail[16] = {0, 0, 0, 123, 62, 50, 0, 33, 0, 17, 16, 12, 10, 8, 6, 4}; -static ssize_t ad7793_read_frequency(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad7793_state *st = iio_priv(indio_dev); - - return sprintf(buf, "%d\n", - st->chip_info->sample_freq_avail[AD7793_MODE_RATE(st->mode)]); -} - -static ssize_t ad7793_write_frequency(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad7793_state *st = iio_priv(indio_dev); - long lval; - int i, ret; - - ret = kstrtol(buf, 10, &lval); - if (ret) - return ret; - - if (lval == 0) - return -EINVAL; - - for (i = 0; i < 16; i++) - if (lval == st->chip_info->sample_freq_avail[i]) - break; - if (i == 16) - return -EINVAL; - - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; - st->mode &= ~AD7793_MODE_RATE(-1); - st->mode |= AD7793_MODE_RATE(i); - ad_sd_write_reg(&st->sd, AD7793_REG_MODE, sizeof(st->mode), st->mode); - iio_device_release_direct_mode(indio_dev); - - return len; -} - -static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, - ad7793_read_frequency, - ad7793_write_frequency); - static IIO_CONST_ATTR_SAMP_FREQ_AVAIL( "470 242 123 62 50 39 33 19 17 16 12 10 8 6 4"); @@ -424,7 +375,6 @@ static IIO_DEVICE_ATTR_NAMED(in_m_in_scale_available, ad7793_show_scale_available, NULL, 0); static struct attribute *ad7793_attributes[] = { - &iio_dev_attr_sampling_frequency.dev_attr.attr, &iio_const_attr_sampling_frequency_available.dev_attr.attr, &iio_dev_attr_in_m_in_scale_available.dev_attr.attr, NULL @@ -435,7 +385,6 @@ static const struct attribute_group ad7793_attribute_group = { }; static struct attribute *ad7797_attributes[] = { - &iio_dev_attr_sampling_frequency.dev_attr.attr, &iio_const_attr_sampling_frequency_available_ad7797.dev_attr.attr, NULL }; @@ -505,6 +454,10 @@ static int ad7793_read_raw(struct iio_dev *indio_dev, *val -= offset; } return IIO_VAL_INT; + case IIO_CHAN_INFO_SAMP_FREQ: + *val = st->chip_info + ->sample_freq_avail[AD7793_MODE_RATE(st->mode)]; + return IIO_VAL_INT; } return -EINVAL; } @@ -542,6 +495,26 @@ static int ad7793_write_raw(struct iio_dev *indio_dev, break; } break; + case IIO_CHAN_INFO_SAMP_FREQ: + if (!val) { + ret = -EINVAL; + break; + } + + for (i = 0; i < 16; i++) + if (val == st->chip_info->sample_freq_avail[i]) + break; + + if (i == 16) { + ret = -EINVAL; + break; + } + + st->mode &= ~AD7793_MODE_RATE(-1); + st->mode |= AD7793_MODE_RATE(i); + ad_sd_write_reg(&st->sd, AD7793_REG_MODE, sizeof(st->mode), + st->mode); + break; default: ret = -EINVAL; } diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c index 4eff8351ce29..8729d6524b4d 100644 --- a/drivers/iio/adc/at91-sama5d2_adc.c +++ b/drivers/iio/adc/at91-sama5d2_adc.c @@ -333,6 +333,27 @@ static const struct iio_chan_spec at91_adc_channels[] = { + AT91_SAMA5D2_DIFF_CHAN_CNT + 1), }; +static int at91_adc_chan_xlate(struct iio_dev *indio_dev, int chan) +{ + int i; + + for (i = 0; i < indio_dev->num_channels; i++) { + if (indio_dev->channels[i].scan_index == chan) + return i; + } + return -EINVAL; +} + +static inline struct iio_chan_spec const * +at91_adc_chan_get(struct iio_dev *indio_dev, int chan) +{ + int index = at91_adc_chan_xlate(indio_dev, chan); + + if (index < 0) + return NULL; + return indio_dev->channels + index; +} + static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state) { struct iio_dev *indio = iio_trigger_get_drvdata(trig); @@ -350,8 +371,10 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state) at91_adc_writel(st, AT91_SAMA5D2_TRGR, status); for_each_set_bit(bit, indio->active_scan_mask, indio->num_channels) { - struct iio_chan_spec const *chan = indio->channels + bit; + struct iio_chan_spec const *chan = at91_adc_chan_get(indio, bit); + if (!chan) + continue; if (state) { at91_adc_writel(st, AT91_SAMA5D2_CHER, BIT(chan->channel)); @@ -448,7 +471,11 @@ static int at91_adc_dma_start(struct iio_dev *indio_dev) for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->num_channels) { - struct iio_chan_spec const *chan = indio_dev->channels + bit; + struct iio_chan_spec const *chan = + at91_adc_chan_get(indio_dev, bit); + + if (!chan) + continue; st->dma_st.rx_buf_sz += chan->scan_type.storagebits / 8; } @@ -526,8 +553,11 @@ static int at91_adc_buffer_predisable(struct iio_dev *indio_dev) */ for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->num_channels) { - struct iio_chan_spec const *chan = indio_dev->channels + bit; + struct iio_chan_spec const *chan = + at91_adc_chan_get(indio_dev, bit); + if (!chan) + continue; if (st->dma_st.dma_chan) at91_adc_readl(st, chan->address); } @@ -587,8 +617,11 @@ static void at91_adc_trigger_handler_nodma(struct iio_dev *indio_dev, for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->num_channels) { - struct iio_chan_spec const *chan = indio_dev->channels + bit; + struct iio_chan_spec const *chan = + at91_adc_chan_get(indio_dev, bit); + if (!chan) + continue; st->buffer[i] = at91_adc_readl(st, chan->address); i++; } diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c index 01422d11753c..b28a716a23b2 100644 --- a/drivers/iio/adc/stm32-dfsdm-adc.c +++ b/drivers/iio/adc/stm32-dfsdm-adc.c @@ -144,6 +144,7 @@ static int stm32_dfsdm_set_osrs(struct stm32_dfsdm_filter *fl, * Leave as soon as if exact resolution if reached. * Otherwise the higher resolution below 32 bits is kept. */ + fl->res = 0; for (fosr = 1; fosr <= DFSDM_MAX_FL_OVERSAMPLING; fosr++) { for (iosr = 1; iosr <= DFSDM_MAX_INT_OVERSAMPLING; iosr++) { if (fast) @@ -193,7 +194,7 @@ static int stm32_dfsdm_set_osrs(struct stm32_dfsdm_filter *fl, } } - if (!fl->fosr) + if (!fl->res) return -EINVAL; return 0; @@ -770,7 +771,7 @@ static int stm32_dfsdm_write_raw(struct iio_dev *indio_dev, struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id]; struct stm32_dfsdm_channel *ch = &adc->dfsdm->ch_list[chan->channel]; - unsigned int spi_freq = adc->spi_freq; + unsigned int spi_freq; int ret = -EINVAL; switch (mask) { @@ -784,8 +785,18 @@ static int stm32_dfsdm_write_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_SAMP_FREQ: if (!val) return -EINVAL; - if (ch->src != DFSDM_CHANNEL_SPI_CLOCK_EXTERNAL) + + switch (ch->src) { + case DFSDM_CHANNEL_SPI_CLOCK_INTERNAL: spi_freq = adc->dfsdm->spi_master_freq; + break; + case DFSDM_CHANNEL_SPI_CLOCK_INTERNAL_DIV2_FALLING: + case DFSDM_CHANNEL_SPI_CLOCK_INTERNAL_DIV2_RISING: + spi_freq = adc->dfsdm->spi_master_freq / 2; + break; + default: + spi_freq = adc->spi_freq; + } if (spi_freq % val) dev_warn(&indio_dev->dev, diff --git a/drivers/iio/buffer/industrialio-buffer-dma.c b/drivers/iio/buffer/industrialio-buffer-dma.c index 05e0c353e089..b32bf57910ca 100644 --- a/drivers/iio/buffer/industrialio-buffer-dma.c +++ b/drivers/iio/buffer/industrialio-buffer-dma.c @@ -587,7 +587,7 @@ EXPORT_SYMBOL_GPL(iio_dma_buffer_set_bytes_per_datum); * Should be used as the set_length callback for iio_buffer_access_ops * struct for DMA buffers. */ -int iio_dma_buffer_set_length(struct iio_buffer *buffer, int length) +int iio_dma_buffer_set_length(struct iio_buffer *buffer, unsigned int length) { /* Avoid an invalid state */ if (length < 2) diff --git a/drivers/iio/buffer/kfifo_buf.c b/drivers/iio/buffer/kfifo_buf.c index 047fe757ab97..70c302a93d7f 100644 --- a/drivers/iio/buffer/kfifo_buf.c +++ b/drivers/iio/buffer/kfifo_buf.c @@ -22,11 +22,18 @@ struct iio_kfifo { #define iio_to_kfifo(r) container_of(r, struct iio_kfifo, buffer) static inline int __iio_allocate_kfifo(struct iio_kfifo *buf, - int bytes_per_datum, int length) + size_t bytes_per_datum, unsigned int length) { if ((length == 0) || (bytes_per_datum == 0)) return -EINVAL; + /* + * Make sure we don't overflow an unsigned int after kfifo rounds up to + * the next power of 2. + */ + if (roundup_pow_of_two(length) > UINT_MAX / bytes_per_datum) + return -EINVAL; + return __kfifo_alloc((struct __kfifo *)&buf->kf, length, bytes_per_datum, GFP_KERNEL); } @@ -67,7 +74,7 @@ static int iio_set_bytes_per_datum_kfifo(struct iio_buffer *r, size_t bpd) return 0; } -static int iio_set_length_kfifo(struct iio_buffer *r, int length) +static int iio_set_length_kfifo(struct iio_buffer *r, unsigned int length) { /* Avoid an invalid state */ if (length < 2) diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c index cfb6588565ba..4905a997a7ec 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c @@ -178,14 +178,14 @@ int hid_sensor_power_state(struct hid_sensor_common *st, bool state) #ifdef CONFIG_PM int ret; - atomic_set(&st->user_requested_state, state); - if (atomic_add_unless(&st->runtime_pm_enable, 1, 1)) pm_runtime_enable(&st->pdev->dev); - if (state) + if (state) { + atomic_inc(&st->user_requested_state); ret = pm_runtime_get_sync(&st->pdev->dev); - else { + } else { + atomic_dec(&st->user_requested_state); pm_runtime_mark_last_busy(&st->pdev->dev); pm_runtime_use_autosuspend(&st->pdev->dev); ret = pm_runtime_put_autosuspend(&st->pdev->dev); diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c index fb2d347f760f..ecc55e98ddd3 100644 --- a/drivers/infiniband/core/cache.c +++ b/drivers/infiniband/core/cache.c @@ -502,7 +502,7 @@ static int __ib_cache_gid_get(struct ib_device *ib_dev, u8 port, int index, return -EINVAL; if (table->data_vec[index].props & GID_TABLE_ENTRY_INVALID) - return -EAGAIN; + return -EINVAL; memcpy(gid, &table->data_vec[index].gid, sizeof(*gid)); if (attr) { diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c index 9a4e899d94b3..2b6c9b516070 100644 --- a/drivers/infiniband/core/umem.c +++ b/drivers/infiniband/core/umem.c @@ -119,7 +119,6 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, umem->length = size; umem->address = addr; umem->page_shift = PAGE_SHIFT; - umem->pid = get_task_pid(current, PIDTYPE_PID); /* * We ask for writable memory if any of the following * access flags are set. "Local write" and "remote write" @@ -132,7 +131,6 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, IB_ACCESS_REMOTE_ATOMIC | IB_ACCESS_MW_BIND)); if (access & IB_ACCESS_ON_DEMAND) { - put_pid(umem->pid); ret = ib_umem_odp_get(context, umem, access); if (ret) { kfree(umem); @@ -148,7 +146,6 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, page_list = (struct page **) __get_free_page(GFP_KERNEL); if (!page_list) { - put_pid(umem->pid); kfree(umem); return ERR_PTR(-ENOMEM); } @@ -231,7 +228,6 @@ out: if (ret < 0) { if (need_release) __ib_umem_release(context->device, umem, 0); - put_pid(umem->pid); kfree(umem); } else current->mm->pinned_vm = locked; @@ -274,8 +270,7 @@ void ib_umem_release(struct ib_umem *umem) __ib_umem_release(umem->context->device, umem, 1); - task = get_pid_task(umem->pid, PIDTYPE_PID); - put_pid(umem->pid); + task = get_pid_task(umem->context->tgid, PIDTYPE_PID); if (!task) goto out; mm = get_task_mm(task); diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c index f6c739ec8b62..20b9f31052bf 100644 --- a/drivers/infiniband/hw/bnxt_re/main.c +++ b/drivers/infiniband/hw/bnxt_re/main.c @@ -185,12 +185,65 @@ static void bnxt_re_shutdown(void *p) bnxt_re_ib_unreg(rdev, false); } +static void bnxt_re_stop_irq(void *handle) +{ + struct bnxt_re_dev *rdev = (struct bnxt_re_dev *)handle; + struct bnxt_qplib_rcfw *rcfw = &rdev->rcfw; + struct bnxt_qplib_nq *nq; + int indx; + + for (indx = BNXT_RE_NQ_IDX; indx < rdev->num_msix; indx++) { + nq = &rdev->nq[indx - 1]; + bnxt_qplib_nq_stop_irq(nq, false); + } + + bnxt_qplib_rcfw_stop_irq(rcfw, false); +} + +static void bnxt_re_start_irq(void *handle, struct bnxt_msix_entry *ent) +{ + struct bnxt_re_dev *rdev = (struct bnxt_re_dev *)handle; + struct bnxt_msix_entry *msix_ent = rdev->msix_entries; + struct bnxt_qplib_rcfw *rcfw = &rdev->rcfw; + struct bnxt_qplib_nq *nq; + int indx, rc; + + if (!ent) { + /* Not setting the f/w timeout bit in rcfw. + * During the driver unload the first command + * to f/w will timeout and that will set the + * timeout bit. + */ + dev_err(rdev_to_dev(rdev), "Failed to re-start IRQs\n"); + return; + } + + /* Vectors may change after restart, so update with new vectors + * in device sctructure. + */ + for (indx = 0; indx < rdev->num_msix; indx++) + rdev->msix_entries[indx].vector = ent[indx].vector; + + bnxt_qplib_rcfw_start_irq(rcfw, msix_ent[BNXT_RE_AEQ_IDX].vector, + false); + for (indx = BNXT_RE_NQ_IDX ; indx < rdev->num_msix; indx++) { + nq = &rdev->nq[indx - 1]; + rc = bnxt_qplib_nq_start_irq(nq, indx - 1, + msix_ent[indx].vector, false); + if (rc) + dev_warn(rdev_to_dev(rdev), + "Failed to reinit NQ index %d\n", indx - 1); + } +} + static struct bnxt_ulp_ops bnxt_re_ulp_ops = { .ulp_async_notifier = NULL, .ulp_stop = bnxt_re_stop, .ulp_start = bnxt_re_start, .ulp_sriov_config = bnxt_re_sriov_config, - .ulp_shutdown = bnxt_re_shutdown + .ulp_shutdown = bnxt_re_shutdown, + .ulp_irq_stop = bnxt_re_stop_irq, + .ulp_irq_restart = bnxt_re_start_irq }; /* RoCE -> Net driver */ diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c index 3a78faba8d91..50d8f1fc98d5 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c @@ -336,22 +336,32 @@ static irqreturn_t bnxt_qplib_nq_irq(int irq, void *dev_instance) return IRQ_HANDLED; } +void bnxt_qplib_nq_stop_irq(struct bnxt_qplib_nq *nq, bool kill) +{ + tasklet_disable(&nq->worker); + /* Mask h/w interrupt */ + NQ_DB(nq->bar_reg_iomem, nq->hwq.cons, nq->hwq.max_elements); + /* Sync with last running IRQ handler */ + synchronize_irq(nq->vector); + if (kill) + tasklet_kill(&nq->worker); + if (nq->requested) { + irq_set_affinity_hint(nq->vector, NULL); + free_irq(nq->vector, nq); + nq->requested = false; + } +} + void bnxt_qplib_disable_nq(struct bnxt_qplib_nq *nq) { if (nq->cqn_wq) { destroy_workqueue(nq->cqn_wq); nq->cqn_wq = NULL; } + /* Make sure the HW is stopped! */ - synchronize_irq(nq->vector); - tasklet_disable(&nq->worker); - tasklet_kill(&nq->worker); + bnxt_qplib_nq_stop_irq(nq, true); - if (nq->requested) { - irq_set_affinity_hint(nq->vector, NULL); - free_irq(nq->vector, nq); - nq->requested = false; - } if (nq->bar_reg_iomem) iounmap(nq->bar_reg_iomem); nq->bar_reg_iomem = NULL; @@ -361,6 +371,40 @@ void bnxt_qplib_disable_nq(struct bnxt_qplib_nq *nq) nq->vector = 0; } +int bnxt_qplib_nq_start_irq(struct bnxt_qplib_nq *nq, int nq_indx, + int msix_vector, bool need_init) +{ + int rc; + + if (nq->requested) + return -EFAULT; + + nq->vector = msix_vector; + if (need_init) + tasklet_init(&nq->worker, bnxt_qplib_service_nq, + (unsigned long)nq); + else + tasklet_enable(&nq->worker); + + snprintf(nq->name, sizeof(nq->name), "bnxt_qplib_nq-%d", nq_indx); + rc = request_irq(nq->vector, bnxt_qplib_nq_irq, 0, nq->name, nq); + if (rc) + return rc; + + cpumask_clear(&nq->mask); + cpumask_set_cpu(nq_indx, &nq->mask); + rc = irq_set_affinity_hint(nq->vector, &nq->mask); + if (rc) { + dev_warn(&nq->pdev->dev, + "QPLIB: set affinity failed; vector: %d nq_idx: %d\n", + nq->vector, nq_indx); + } + nq->requested = true; + NQ_DB_REARM(nq->bar_reg_iomem, nq->hwq.cons, nq->hwq.max_elements); + + return rc; +} + int bnxt_qplib_enable_nq(struct pci_dev *pdev, struct bnxt_qplib_nq *nq, int nq_idx, int msix_vector, int bar_reg_offset, int (*cqn_handler)(struct bnxt_qplib_nq *nq, @@ -372,41 +416,17 @@ int bnxt_qplib_enable_nq(struct pci_dev *pdev, struct bnxt_qplib_nq *nq, resource_size_t nq_base; int rc = -1; - nq->pdev = pdev; - nq->vector = msix_vector; if (cqn_handler) nq->cqn_handler = cqn_handler; if (srqn_handler) nq->srqn_handler = srqn_handler; - tasklet_init(&nq->worker, bnxt_qplib_service_nq, (unsigned long)nq); - /* Have a task to schedule CQ notifiers in post send case */ nq->cqn_wq = create_singlethread_workqueue("bnxt_qplib_nq"); if (!nq->cqn_wq) - goto fail; - - nq->requested = false; - memset(nq->name, 0, 32); - sprintf(nq->name, "bnxt_qplib_nq-%d", nq_idx); - rc = request_irq(nq->vector, bnxt_qplib_nq_irq, 0, nq->name, nq); - if (rc) { - dev_err(&nq->pdev->dev, - "Failed to request IRQ for NQ: %#x", rc); - goto fail; - } - - cpumask_clear(&nq->mask); - cpumask_set_cpu(nq_idx, &nq->mask); - rc = irq_set_affinity_hint(nq->vector, &nq->mask); - if (rc) { - dev_warn(&nq->pdev->dev, - "QPLIB: set affinity failed; vector: %d nq_idx: %d\n", - nq->vector, nq_idx); - } + return -ENOMEM; - nq->requested = true; nq->bar_reg = NQ_CONS_PCI_BAR_REGION; nq->bar_reg_off = bar_reg_offset; nq_base = pci_resource_start(pdev, nq->bar_reg); @@ -419,7 +439,13 @@ int bnxt_qplib_enable_nq(struct pci_dev *pdev, struct bnxt_qplib_nq *nq, rc = -ENOMEM; goto fail; } - NQ_DB_REARM(nq->bar_reg_iomem, nq->hwq.cons, nq->hwq.max_elements); + + rc = bnxt_qplib_nq_start_irq(nq, nq_idx, msix_vector, true); + if (rc) { + dev_err(&nq->pdev->dev, + "QPLIB: Failed to request irq for nq-idx %d", nq_idx); + goto fail; + } return 0; fail: diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.h b/drivers/infiniband/hw/bnxt_re/qplib_fp.h index ade9f13c0fd1..72352ca80ace 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_fp.h +++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.h @@ -467,7 +467,10 @@ struct bnxt_qplib_nq_work { struct bnxt_qplib_cq *cq; }; +void bnxt_qplib_nq_stop_irq(struct bnxt_qplib_nq *nq, bool kill); void bnxt_qplib_disable_nq(struct bnxt_qplib_nq *nq); +int bnxt_qplib_nq_start_irq(struct bnxt_qplib_nq *nq, int nq_indx, + int msix_vector, bool need_init); int bnxt_qplib_enable_nq(struct pci_dev *pdev, struct bnxt_qplib_nq *nq, int nq_idx, int msix_vector, int bar_reg_offset, int (*cqn_handler)(struct bnxt_qplib_nq *nq, diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c index 80027a494730..2852d350ada1 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c @@ -582,19 +582,29 @@ fail: return -ENOMEM; } -void bnxt_qplib_disable_rcfw_channel(struct bnxt_qplib_rcfw *rcfw) +void bnxt_qplib_rcfw_stop_irq(struct bnxt_qplib_rcfw *rcfw, bool kill) { - unsigned long indx; - - /* Make sure the HW channel is stopped! */ - synchronize_irq(rcfw->vector); tasklet_disable(&rcfw->worker); - tasklet_kill(&rcfw->worker); + /* Mask h/w interrupts */ + CREQ_DB(rcfw->creq_bar_reg_iomem, rcfw->creq.cons, + rcfw->creq.max_elements); + /* Sync with last running IRQ-handler */ + synchronize_irq(rcfw->vector); + if (kill) + tasklet_kill(&rcfw->worker); if (rcfw->requested) { free_irq(rcfw->vector, rcfw); rcfw->requested = false; } +} + +void bnxt_qplib_disable_rcfw_channel(struct bnxt_qplib_rcfw *rcfw) +{ + unsigned long indx; + + bnxt_qplib_rcfw_stop_irq(rcfw, true); + if (rcfw->cmdq_bar_reg_iomem) iounmap(rcfw->cmdq_bar_reg_iomem); rcfw->cmdq_bar_reg_iomem = NULL; @@ -614,6 +624,31 @@ void bnxt_qplib_disable_rcfw_channel(struct bnxt_qplib_rcfw *rcfw) rcfw->vector = 0; } +int bnxt_qplib_rcfw_start_irq(struct bnxt_qplib_rcfw *rcfw, int msix_vector, + bool need_init) +{ + int rc; + + if (rcfw->requested) + return -EFAULT; + + rcfw->vector = msix_vector; + if (need_init) + tasklet_init(&rcfw->worker, + bnxt_qplib_service_creq, (unsigned long)rcfw); + else + tasklet_enable(&rcfw->worker); + rc = request_irq(rcfw->vector, bnxt_qplib_creq_irq, 0, + "bnxt_qplib_creq", rcfw); + if (rc) + return rc; + rcfw->requested = true; + CREQ_DB_REARM(rcfw->creq_bar_reg_iomem, rcfw->creq.cons, + rcfw->creq.max_elements); + + return 0; +} + int bnxt_qplib_enable_rcfw_channel(struct pci_dev *pdev, struct bnxt_qplib_rcfw *rcfw, int msix_vector, @@ -675,27 +710,17 @@ int bnxt_qplib_enable_rcfw_channel(struct pci_dev *pdev, rcfw->creq_qp_event_processed = 0; rcfw->creq_func_event_processed = 0; - rcfw->vector = msix_vector; if (aeq_handler) rcfw->aeq_handler = aeq_handler; + init_waitqueue_head(&rcfw->waitq); - tasklet_init(&rcfw->worker, bnxt_qplib_service_creq, - (unsigned long)rcfw); - - rcfw->requested = false; - rc = request_irq(rcfw->vector, bnxt_qplib_creq_irq, 0, - "bnxt_qplib_creq", rcfw); + rc = bnxt_qplib_rcfw_start_irq(rcfw, msix_vector, true); if (rc) { dev_err(&rcfw->pdev->dev, "QPLIB: Failed to request IRQ for CREQ rc = 0x%x", rc); bnxt_qplib_disable_rcfw_channel(rcfw); return rc; } - rcfw->requested = true; - - init_waitqueue_head(&rcfw->waitq); - - CREQ_DB_REARM(rcfw->creq_bar_reg_iomem, 0, rcfw->creq.max_elements); init.cmdq_pbl = cpu_to_le64(rcfw->cmdq.pbl[PBL_LVL_0].pg_map_arr[0]); init.cmdq_size_cmdq_lvl = cpu_to_le16( diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h index c7cce2e4185e..46416dfe8830 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h +++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h @@ -195,7 +195,10 @@ struct bnxt_qplib_rcfw { void bnxt_qplib_free_rcfw_channel(struct bnxt_qplib_rcfw *rcfw); int bnxt_qplib_alloc_rcfw_channel(struct pci_dev *pdev, struct bnxt_qplib_rcfw *rcfw, int qp_tbl_sz); +void bnxt_qplib_rcfw_stop_irq(struct bnxt_qplib_rcfw *rcfw, bool kill); void bnxt_qplib_disable_rcfw_channel(struct bnxt_qplib_rcfw *rcfw); +int bnxt_qplib_rcfw_start_irq(struct bnxt_qplib_rcfw *rcfw, int msix_vector, + bool need_init); int bnxt_qplib_enable_rcfw_channel(struct pci_dev *pdev, struct bnxt_qplib_rcfw *rcfw, int msix_vector, diff --git a/drivers/infiniband/hw/cxgb4/mem.c b/drivers/infiniband/hw/cxgb4/mem.c index e90f2fd8dc16..1445918e3239 100644 --- a/drivers/infiniband/hw/cxgb4/mem.c +++ b/drivers/infiniband/hw/cxgb4/mem.c @@ -489,10 +489,10 @@ struct ib_mr *c4iw_get_dma_mr(struct ib_pd *pd, int acc) err_dereg_mem: dereg_mem(&rhp->rdev, mhp->attr.stag, mhp->attr.pbl_size, mhp->attr.pbl_addr, mhp->dereg_skb, mhp->wr_waitp); -err_free_wr_wait: - c4iw_put_wr_wait(mhp->wr_waitp); err_free_skb: kfree_skb(mhp->dereg_skb); +err_free_wr_wait: + c4iw_put_wr_wait(mhp->wr_waitp); err_free_mhp: kfree(mhp); return ERR_PTR(ret); diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c index e6a60fa59f2b..e6bdd0c1e80a 100644 --- a/drivers/infiniband/hw/hfi1/chip.c +++ b/drivers/infiniband/hw/hfi1/chip.c @@ -5944,6 +5944,7 @@ static void is_sendctxt_err_int(struct hfi1_devdata *dd, u64 status; u32 sw_index; int i = 0; + unsigned long irq_flags; sw_index = dd->hw_to_sw[hw_context]; if (sw_index >= dd->num_send_contexts) { @@ -5953,10 +5954,12 @@ static void is_sendctxt_err_int(struct hfi1_devdata *dd, return; } sci = &dd->send_contexts[sw_index]; + spin_lock_irqsave(&dd->sc_lock, irq_flags); sc = sci->sc; if (!sc) { dd_dev_err(dd, "%s: context %u(%u): no sc?\n", __func__, sw_index, hw_context); + spin_unlock_irqrestore(&dd->sc_lock, irq_flags); return; } @@ -5978,6 +5981,7 @@ static void is_sendctxt_err_int(struct hfi1_devdata *dd, */ if (sc->type != SC_USER) queue_work(dd->pport->hfi1_wq, &sc->halt_work); + spin_unlock_irqrestore(&dd->sc_lock, irq_flags); /* * Update the counters for the corresponding status bits. diff --git a/drivers/infiniband/hw/hns/hns_roce_cq.c b/drivers/infiniband/hw/hns/hns_roce_cq.c index 14734d0d0b76..3a485f50fede 100644 --- a/drivers/infiniband/hw/hns/hns_roce_cq.c +++ b/drivers/infiniband/hw/hns/hns_roce_cq.c @@ -377,6 +377,7 @@ struct ib_cq *hns_roce_ib_create_cq(struct ib_device *ib_dev, hr_cq->set_ci_db = hr_cq->db.db_record; *hr_cq->set_ci_db = 0; + hr_cq->db_en = 1; } /* Init mmt table and write buff address to mtt table */ diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c index 47e1b6ac1e1a..8013d69c5ac4 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c @@ -722,6 +722,7 @@ static int hns_roce_v1_rsv_lp_qp(struct hns_roce_dev *hr_dev) free_mr->mr_free_pd = to_hr_pd(pd); free_mr->mr_free_pd->ibpd.device = &hr_dev->ib_dev; free_mr->mr_free_pd->ibpd.uobject = NULL; + free_mr->mr_free_pd->ibpd.__internal_mr = NULL; atomic_set(&free_mr->mr_free_pd->ibpd.usecnt, 0); attr.qp_access_flags = IB_ACCESS_REMOTE_WRITE; @@ -1036,7 +1037,7 @@ static void hns_roce_v1_mr_free_work_fn(struct work_struct *work) do { ret = hns_roce_v1_poll_cq(&mr_free_cq->ib_cq, ne, wc); - if (ret < 0) { + if (ret < 0 && hr_qp) { dev_err(dev, "(qp:0x%lx) starts, Poll cqe failed(%d) for mr 0x%x free! Remain %d cqe\n", hr_qp->qpn, ret, hr_mr->key, ne); diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index 25916e8522ed..1f0965bb64ee 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -142,8 +142,8 @@ static int hns_roce_v2_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, unsigned long flags; unsigned int ind; void *wqe = NULL; - u32 tmp_len = 0; bool loopback; + u32 tmp_len; int ret = 0; u8 *smac; int nreq; @@ -189,6 +189,7 @@ static int hns_roce_v2_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, owner_bit = ~(((qp->sq.head + nreq) >> ilog2(qp->sq.wqe_cnt)) & 0x1); + tmp_len = 0; /* Corresponding to the QP type, wqe process separately */ if (ibqp->qp_type == IB_QPT_GSI) { @@ -547,16 +548,20 @@ static int hns_roce_v2_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr, } if (i < hr_qp->rq.max_gs) { - dseg[i].lkey = cpu_to_le32(HNS_ROCE_INVALID_LKEY); - dseg[i].addr = 0; + dseg->lkey = cpu_to_le32(HNS_ROCE_INVALID_LKEY); + dseg->addr = 0; } /* rq support inline data */ - sge_list = hr_qp->rq_inl_buf.wqe_list[ind].sg_list; - hr_qp->rq_inl_buf.wqe_list[ind].sge_cnt = (u32)wr->num_sge; - for (i = 0; i < wr->num_sge; i++) { - sge_list[i].addr = (void *)(u64)wr->sg_list[i].addr; - sge_list[i].len = wr->sg_list[i].length; + if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RQ_INLINE) { + sge_list = hr_qp->rq_inl_buf.wqe_list[ind].sg_list; + hr_qp->rq_inl_buf.wqe_list[ind].sge_cnt = + (u32)wr->num_sge; + for (i = 0; i < wr->num_sge; i++) { + sge_list[i].addr = + (void *)(u64)wr->sg_list[i].addr; + sge_list[i].len = wr->sg_list[i].length; + } } hr_qp->rq.wrid[ind] = wr->wr_id; @@ -613,6 +618,8 @@ static void hns_roce_free_cmq_desc(struct hns_roce_dev *hr_dev, dma_unmap_single(hr_dev->dev, ring->desc_dma_addr, ring->desc_num * sizeof(struct hns_roce_cmq_desc), DMA_BIDIRECTIONAL); + + ring->desc_dma_addr = 0; kfree(ring->desc); } @@ -1081,6 +1088,7 @@ static int hns_roce_v2_profile(struct hns_roce_dev *hr_dev) if (ret) { dev_err(hr_dev->dev, "Configure global param fail, ret = %d.\n", ret); + return ret; } /* Get pf resource owned by every pf */ @@ -1372,6 +1380,8 @@ static int hns_roce_v2_write_mtpt(void *mb_buf, struct hns_roce_mr *mr, roce_set_bit(mpt_entry->byte_12_mw_pa, V2_MPT_BYTE_12_PA_S, mr->type == MR_TYPE_MR ? 0 : 1); + roce_set_bit(mpt_entry->byte_12_mw_pa, V2_MPT_BYTE_12_INNER_PA_VLD_S, + 1); mpt_entry->byte_12_mw_pa = cpu_to_le32(mpt_entry->byte_12_mw_pa); mpt_entry->len_l = cpu_to_le32(lower_32_bits(mr->size)); @@ -2169,6 +2179,7 @@ static void modify_qp_reset_to_init(struct ib_qp *ibqp, struct hns_roce_v2_qp_context *context, struct hns_roce_v2_qp_context *qpc_mask) { + struct hns_roce_dev *hr_dev = to_hr_dev(ibqp->device); struct hns_roce_qp *hr_qp = to_hr_qp(ibqp); /* @@ -2281,7 +2292,8 @@ static void modify_qp_reset_to_init(struct ib_qp *ibqp, context->rq_db_record_addr = hr_qp->rdb.dma >> 32; qpc_mask->rq_db_record_addr = 0; - roce_set_bit(context->byte_76_srqn_op_en, V2_QPC_BYTE_76_RQIE_S, 1); + roce_set_bit(context->byte_76_srqn_op_en, V2_QPC_BYTE_76_RQIE_S, + (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RQ_INLINE) ? 1 : 0); roce_set_bit(qpc_mask->byte_76_srqn_op_en, V2_QPC_BYTE_76_RQIE_S, 0); roce_set_field(context->byte_80_rnr_rx_cqn, V2_QPC_BYTE_80_RX_CQN_M, @@ -4703,6 +4715,8 @@ static const struct pci_device_id hns_roce_hw_v2_pci_tbl[] = { {0, } }; +MODULE_DEVICE_TABLE(pci, hns_roce_hw_v2_pci_tbl); + static int hns_roce_hw_v2_get_cfg(struct hns_roce_dev *hr_dev, struct hnae3_handle *handle) { diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c index 9d48bc07a9e6..96fb6a9ed93c 100644 --- a/drivers/infiniband/hw/hns/hns_roce_main.c +++ b/drivers/infiniband/hw/hns/hns_roce_main.c @@ -199,7 +199,7 @@ static int hns_roce_query_device(struct ib_device *ib_dev, memset(props, 0, sizeof(*props)); - props->sys_image_guid = cpu_to_be32(hr_dev->sys_image_guid); + props->sys_image_guid = cpu_to_be64(hr_dev->sys_image_guid); props->max_mr_size = (u64)(~(0ULL)); props->page_size_cap = hr_dev->caps.page_size_cap; props->vendor_id = hr_dev->vendor_id; diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c index d4aad34c21e2..baaf906f7c2e 100644 --- a/drivers/infiniband/hw/hns/hns_roce_qp.c +++ b/drivers/infiniband/hw/hns/hns_roce_qp.c @@ -660,6 +660,7 @@ static int hns_roce_create_qp_common(struct hns_roce_dev *hr_dev, goto err_rq_sge_list; } *hr_qp->rdb.db_record = 0; + hr_qp->rdb_en = 1; } /* Allocate QP buf */ @@ -955,7 +956,14 @@ int hns_roce_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, } if (cur_state == new_state && cur_state == IB_QPS_RESET) { - ret = 0; + if (hr_dev->caps.min_wqes) { + ret = -EPERM; + dev_err(dev, "cur_state=%d new_state=%d\n", cur_state, + new_state); + } else { + ret = 0; + } + goto out; } diff --git a/drivers/infiniband/hw/i40iw/i40iw.h b/drivers/infiniband/hw/i40iw/i40iw.h index d5d8c1be345a..2f2b4426ded7 100644 --- a/drivers/infiniband/hw/i40iw/i40iw.h +++ b/drivers/infiniband/hw/i40iw/i40iw.h @@ -207,6 +207,7 @@ struct i40iw_msix_vector { u32 irq; u32 cpu_affinity; u32 ceq_id; + cpumask_t mask; }; struct l2params_work { diff --git a/drivers/infiniband/hw/i40iw/i40iw_cm.c b/drivers/infiniband/hw/i40iw/i40iw_cm.c index 4cfa8f4647e2..f7c6fd9ff6e2 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_cm.c +++ b/drivers/infiniband/hw/i40iw/i40iw_cm.c @@ -2093,7 +2093,7 @@ static int i40iw_addr_resolve_neigh_ipv6(struct i40iw_device *iwdev, if (netif_is_bond_slave(netdev)) netdev = netdev_master_upper_dev_get(netdev); - neigh = dst_neigh_lookup(dst, &dst_addr); + neigh = dst_neigh_lookup(dst, dst_addr.sin6_addr.in6_u.u6_addr32); rcu_read_lock(); if (neigh) { diff --git a/drivers/infiniband/hw/i40iw/i40iw_hw.c b/drivers/infiniband/hw/i40iw/i40iw_hw.c index 6139836fb533..c9f62ca7643c 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_hw.c +++ b/drivers/infiniband/hw/i40iw/i40iw_hw.c @@ -331,7 +331,7 @@ void i40iw_process_aeq(struct i40iw_device *iwdev) switch (info->ae_id) { case I40IW_AE_LLP_FIN_RECEIVED: if (qp->term_flags) - continue; + break; if (atomic_inc_return(&iwqp->close_timer_started) == 1) { iwqp->hw_tcp_state = I40IW_TCP_STATE_CLOSE_WAIT; if ((iwqp->hw_tcp_state == I40IW_TCP_STATE_CLOSE_WAIT) && @@ -360,7 +360,7 @@ void i40iw_process_aeq(struct i40iw_device *iwdev) break; case I40IW_AE_LLP_CONNECTION_RESET: if (atomic_read(&iwqp->close_timer_started)) - continue; + break; i40iw_cm_disconn(iwqp); break; case I40IW_AE_QP_SUSPEND_COMPLETE: diff --git a/drivers/infiniband/hw/i40iw/i40iw_main.c b/drivers/infiniband/hw/i40iw/i40iw_main.c index 9cd0d3ef9057..05001e6da1f8 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_main.c +++ b/drivers/infiniband/hw/i40iw/i40iw_main.c @@ -687,7 +687,6 @@ static enum i40iw_status_code i40iw_configure_ceq_vector(struct i40iw_device *iw struct i40iw_msix_vector *msix_vec) { enum i40iw_status_code status; - cpumask_t mask; if (iwdev->msix_shared && !ceq_id) { tasklet_init(&iwdev->dpc_tasklet, i40iw_dpc, (unsigned long)iwdev); @@ -697,9 +696,9 @@ static enum i40iw_status_code i40iw_configure_ceq_vector(struct i40iw_device *iw status = request_irq(msix_vec->irq, i40iw_ceq_handler, 0, "CEQ", iwceq); } - cpumask_clear(&mask); - cpumask_set_cpu(msix_vec->cpu_affinity, &mask); - irq_set_affinity_hint(msix_vec->irq, &mask); + cpumask_clear(&msix_vec->mask); + cpumask_set_cpu(msix_vec->cpu_affinity, &msix_vec->mask); + irq_set_affinity_hint(msix_vec->irq, &msix_vec->mask); if (status) { i40iw_pr_err("ceq irq config fail\n"); diff --git a/drivers/infiniband/hw/i40iw/i40iw_verbs.c b/drivers/infiniband/hw/i40iw/i40iw_verbs.c index 40e4f5ab2b46..68679ad4c6da 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_verbs.c +++ b/drivers/infiniband/hw/i40iw/i40iw_verbs.c @@ -394,6 +394,7 @@ static struct i40iw_pbl *i40iw_get_pbl(unsigned long va, list_for_each_entry(iwpbl, pbl_list, list) { if (iwpbl->user_base == va) { + iwpbl->on_list = false; list_del(&iwpbl->list); return iwpbl; } @@ -614,6 +615,7 @@ static struct ib_qp *i40iw_create_qp(struct ib_pd *ibpd, return ERR_PTR(-ENOMEM); iwqp = (struct i40iw_qp *)mem; + iwqp->allocated_buffer = mem; qp = &iwqp->sc_qp; qp->back_qp = (void *)iwqp; qp->push_idx = I40IW_INVALID_PUSH_PAGE_INDEX; @@ -642,7 +644,6 @@ static struct ib_qp *i40iw_create_qp(struct ib_pd *ibpd, goto error; } - iwqp->allocated_buffer = mem; iwqp->iwdev = iwdev; iwqp->iwpd = iwpd; iwqp->ibqp.qp_num = qp_num; @@ -1898,6 +1899,7 @@ static struct ib_mr *i40iw_reg_user_mr(struct ib_pd *pd, goto error; spin_lock_irqsave(&ucontext->qp_reg_mem_list_lock, flags); list_add_tail(&iwpbl->list, &ucontext->qp_reg_mem_list); + iwpbl->on_list = true; spin_unlock_irqrestore(&ucontext->qp_reg_mem_list_lock, flags); break; case IW_MEMREG_TYPE_CQ: @@ -1908,6 +1910,7 @@ static struct ib_mr *i40iw_reg_user_mr(struct ib_pd *pd, spin_lock_irqsave(&ucontext->cq_reg_mem_list_lock, flags); list_add_tail(&iwpbl->list, &ucontext->cq_reg_mem_list); + iwpbl->on_list = true; spin_unlock_irqrestore(&ucontext->cq_reg_mem_list_lock, flags); break; case IW_MEMREG_TYPE_MEM: @@ -2045,14 +2048,18 @@ static void i40iw_del_memlist(struct i40iw_mr *iwmr, switch (iwmr->type) { case IW_MEMREG_TYPE_CQ: spin_lock_irqsave(&ucontext->cq_reg_mem_list_lock, flags); - if (!list_empty(&ucontext->cq_reg_mem_list)) + if (iwpbl->on_list) { + iwpbl->on_list = false; list_del(&iwpbl->list); + } spin_unlock_irqrestore(&ucontext->cq_reg_mem_list_lock, flags); break; case IW_MEMREG_TYPE_QP: spin_lock_irqsave(&ucontext->qp_reg_mem_list_lock, flags); - if (!list_empty(&ucontext->qp_reg_mem_list)) + if (iwpbl->on_list) { + iwpbl->on_list = false; list_del(&iwpbl->list); + } spin_unlock_irqrestore(&ucontext->qp_reg_mem_list_lock, flags); break; default: diff --git a/drivers/infiniband/hw/i40iw/i40iw_verbs.h b/drivers/infiniband/hw/i40iw/i40iw_verbs.h index 9067443cd311..76cf173377ab 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_verbs.h +++ b/drivers/infiniband/hw/i40iw/i40iw_verbs.h @@ -78,6 +78,7 @@ struct i40iw_pbl { }; bool pbl_allocated; + bool on_list; u64 user_base; struct i40iw_pble_alloc pble_alloc; struct i40iw_mr *iwmr; diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index b4d8ff8ab807..69716a7ea993 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -2416,7 +2416,7 @@ static void set_proto(void *outer_c, void *outer_v, u8 mask, u8 val) MLX5_SET(fte_match_set_lyr_2_4, outer_v, ip_protocol, val); } -static void set_flow_label(void *misc_c, void *misc_v, u8 mask, u8 val, +static void set_flow_label(void *misc_c, void *misc_v, u32 mask, u32 val, bool inner) { if (inner) { diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 87b7c1be2a11..2193dc1765fb 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -484,11 +484,6 @@ static int qp_has_rq(struct ib_qp_init_attr *attr) return 1; } -static int first_med_bfreg(void) -{ - return 1; -} - enum { /* this is the first blue flame register in the array of bfregs assigned * to a processes. Since we do not use it for blue flame but rather @@ -514,6 +509,12 @@ static int num_med_bfreg(struct mlx5_ib_dev *dev, return n >= 0 ? n : 0; } +static int first_med_bfreg(struct mlx5_ib_dev *dev, + struct mlx5_bfreg_info *bfregi) +{ + return num_med_bfreg(dev, bfregi) ? 1 : -ENOMEM; +} + static int first_hi_bfreg(struct mlx5_ib_dev *dev, struct mlx5_bfreg_info *bfregi) { @@ -541,10 +542,13 @@ static int alloc_high_class_bfreg(struct mlx5_ib_dev *dev, static int alloc_med_class_bfreg(struct mlx5_ib_dev *dev, struct mlx5_bfreg_info *bfregi) { - int minidx = first_med_bfreg(); + int minidx = first_med_bfreg(dev, bfregi); int i; - for (i = first_med_bfreg(); i < first_hi_bfreg(dev, bfregi); i++) { + if (minidx < 0) + return minidx; + + for (i = minidx; i < first_hi_bfreg(dev, bfregi); i++) { if (bfregi->count[i] < bfregi->count[minidx]) minidx = i; if (!bfregi->count[minidx]) diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index 7d3763b2e01c..3f9afc02d166 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -401,49 +401,47 @@ int qedr_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) { struct qedr_ucontext *ucontext = get_qedr_ucontext(context); struct qedr_dev *dev = get_qedr_dev(context->device); - unsigned long vm_page = vma->vm_pgoff << PAGE_SHIFT; - u64 unmapped_db = dev->db_phys_addr; + unsigned long phys_addr = vma->vm_pgoff << PAGE_SHIFT; unsigned long len = (vma->vm_end - vma->vm_start); - int rc = 0; - bool found; + unsigned long dpi_start; + + dpi_start = dev->db_phys_addr + (ucontext->dpi * ucontext->dpi_size); DP_DEBUG(dev, QEDR_MSG_INIT, - "qedr_mmap called vm_page=0x%lx vm_pgoff=0x%lx unmapped_db=0x%llx db_size=%x, len=%lx\n", - vm_page, vma->vm_pgoff, unmapped_db, dev->db_size, len); - if (vma->vm_start & (PAGE_SIZE - 1)) { - DP_ERR(dev, "Vma_start not page aligned = %ld\n", - vma->vm_start); + "mmap invoked with vm_start=0x%pK, vm_end=0x%pK,vm_pgoff=0x%pK; dpi_start=0x%pK dpi_size=0x%x\n", + (void *)vma->vm_start, (void *)vma->vm_end, + (void *)vma->vm_pgoff, (void *)dpi_start, ucontext->dpi_size); + + if ((vma->vm_start & (PAGE_SIZE - 1)) || (len & (PAGE_SIZE - 1))) { + DP_ERR(dev, + "failed mmap, adrresses must be page aligned: start=0x%pK, end=0x%pK\n", + (void *)vma->vm_start, (void *)vma->vm_end); return -EINVAL; } - found = qedr_search_mmap(ucontext, vm_page, len); - if (!found) { - DP_ERR(dev, "Vma_pgoff not found in mapped array = %ld\n", + if (!qedr_search_mmap(ucontext, phys_addr, len)) { + DP_ERR(dev, "failed mmap, vm_pgoff=0x%lx is not authorized\n", vma->vm_pgoff); return -EINVAL; } - DP_DEBUG(dev, QEDR_MSG_INIT, "Mapping doorbell bar\n"); - - if ((vm_page >= unmapped_db) && (vm_page <= (unmapped_db + - dev->db_size))) { - DP_DEBUG(dev, QEDR_MSG_INIT, "Mapping doorbell bar\n"); - if (vma->vm_flags & VM_READ) { - DP_ERR(dev, "Trying to map doorbell bar for read\n"); - return -EPERM; - } - - vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + if (phys_addr < dpi_start || + ((phys_addr + len) > (dpi_start + ucontext->dpi_size))) { + DP_ERR(dev, + "failed mmap, pages are outside of dpi; page address=0x%pK, dpi_start=0x%pK, dpi_size=0x%x\n", + (void *)phys_addr, (void *)dpi_start, + ucontext->dpi_size); + return -EINVAL; + } - rc = io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, - PAGE_SIZE, vma->vm_page_prot); - } else { - DP_DEBUG(dev, QEDR_MSG_INIT, "Mapping chains\n"); - rc = remap_pfn_range(vma, vma->vm_start, - vma->vm_pgoff, len, vma->vm_page_prot); + if (vma->vm_flags & VM_READ) { + DP_ERR(dev, "failed mmap, cannot map doorbell bar for read\n"); + return -EINVAL; } - DP_DEBUG(dev, QEDR_MSG_INIT, "qedr_mmap return code: %d\n", rc); - return rc; + + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + return io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, len, + vma->vm_page_prot); } struct ib_pd *qedr_alloc_pd(struct ib_device *ibdev, diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.c b/drivers/infiniband/sw/rxe/rxe_verbs.c index 2cb52fd48cf1..73a00a1c06f6 100644 --- a/drivers/infiniband/sw/rxe/rxe_verbs.c +++ b/drivers/infiniband/sw/rxe/rxe_verbs.c @@ -761,7 +761,6 @@ static int rxe_post_send_kernel(struct rxe_qp *qp, struct ib_send_wr *wr, unsigned int mask; unsigned int length = 0; int i; - int must_sched; while (wr) { mask = wr_opcode_mask(wr->opcode, qp); @@ -791,14 +790,7 @@ static int rxe_post_send_kernel(struct rxe_qp *qp, struct ib_send_wr *wr, wr = wr->next; } - /* - * Must sched in case of GSI QP because ib_send_mad() hold irq lock, - * and the requester call ip_local_out_sk() that takes spin_lock_bh. - */ - must_sched = (qp_type(qp) == IB_QPT_GSI) || - (queue_count(qp->sq.queue) > 1); - - rxe_run_task(&qp->req.task, must_sched); + rxe_run_task(&qp->req.task, 1); if (unlikely(qp->req.state == QP_STATE_ERROR)) rxe_run_task(&qp->comp.task, 1); diff --git a/drivers/input/input.c b/drivers/input/input.c index 9785546420a7..6365c1958264 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -1943,8 +1943,7 @@ void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int break; default: - pr_err("input_set_capability: unknown type %u (code %u)\n", - type, code); + pr_err("%s: unknown type %u (code %u)\n", __func__, type, code); dump_stack(); return; } diff --git a/drivers/input/joystick/as5011.c b/drivers/input/joystick/as5011.c index 005d852a06e9..f051993c568e 100644 --- a/drivers/input/joystick/as5011.c +++ b/drivers/input/joystick/as5011.c @@ -269,9 +269,7 @@ static int as5011_probe(struct i2c_client *client, input_dev->id.bustype = BUS_I2C; input_dev->dev.parent = &client->dev; - __set_bit(EV_KEY, input_dev->evbit); - __set_bit(EV_ABS, input_dev->evbit); - __set_bit(BTN_JOYSTICK, input_dev->keybit); + input_set_capability(input_dev, EV_KEY, BTN_JOYSTICK); input_set_abs_params(input_dev, ABS_X, AS5011_MIN_AXIS, AS5011_MAX_AXIS, AS5011_FUZZ, AS5011_FLAT); diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c index 2ffb2e8bdc3b..4e10ffdf8a36 100644 --- a/drivers/input/joystick/gamecon.c +++ b/drivers/input/joystick/gamecon.c @@ -862,7 +862,7 @@ static int gc_setup_pad(struct gc *gc, int idx, int pad_type) case GC_N64: for (i = 0; i < 10; i++) - __set_bit(gc_n64_btn[i], input_dev->keybit); + input_set_capability(input_dev, EV_KEY, gc_n64_btn[i]); for (i = 0; i < 2; i++) { input_set_abs_params(input_dev, ABS_X + i, -127, 126, 0, 2); @@ -879,26 +879,27 @@ static int gc_setup_pad(struct gc *gc, int idx, int pad_type) break; case GC_SNESMOUSE: - __set_bit(BTN_LEFT, input_dev->keybit); - __set_bit(BTN_RIGHT, input_dev->keybit); - __set_bit(REL_X, input_dev->relbit); - __set_bit(REL_Y, input_dev->relbit); + input_set_capability(input_dev, EV_KEY, BTN_LEFT); + input_set_capability(input_dev, EV_KEY, BTN_RIGHT); + input_set_capability(input_dev, EV_REL, REL_X); + input_set_capability(input_dev, EV_REL, REL_Y); break; case GC_SNES: for (i = 4; i < 8; i++) - __set_bit(gc_snes_btn[i], input_dev->keybit); + input_set_capability(input_dev, EV_KEY, gc_snes_btn[i]); /* fall through */ case GC_NES: for (i = 0; i < 4; i++) - __set_bit(gc_snes_btn[i], input_dev->keybit); + input_set_capability(input_dev, EV_KEY, gc_snes_btn[i]); break; case GC_MULTI2: - __set_bit(BTN_THUMB, input_dev->keybit); + input_set_capability(input_dev, EV_KEY, BTN_THUMB); /* fall through */ case GC_MULTI: - __set_bit(BTN_TRIGGER, input_dev->keybit); + input_set_capability(input_dev, EV_KEY, BTN_TRIGGER); + /* fall through */ break; case GC_PSX: @@ -906,15 +907,17 @@ static int gc_setup_pad(struct gc *gc, int idx, int pad_type) input_set_abs_params(input_dev, gc_psx_abs[i], 4, 252, 0, 2); for (i = 0; i < 12; i++) - __set_bit(gc_psx_btn[i], input_dev->keybit); + input_set_capability(input_dev, EV_KEY, gc_psx_btn[i]); + break; break; case GC_DDR: for (i = 0; i < 4; i++) - __set_bit(gc_psx_ddr_btn[i], input_dev->keybit); + input_set_capability(input_dev, EV_KEY, + gc_psx_ddr_btn[i]); for (i = 0; i < 12; i++) - __set_bit(gc_psx_btn[i], input_dev->keybit); + input_set_capability(input_dev, EV_KEY, gc_psx_btn[i]); break; } diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 06e9650b3b30..48e36acbeb49 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -86,8 +86,10 @@ #define XPAD_PKT_LEN 64 -/* xbox d-pads should map to buttons, as is required for DDR pads - but we map them to axes when possible to simplify things */ +/* + * xbox d-pads should map to buttons, as is required for DDR pads + * but we map them to axes when possible to simplify things + */ #define MAP_DPAD_TO_BUTTONS (1 << 0) #define MAP_TRIGGERS_TO_BUTTONS (1 << 1) #define MAP_STICKS_TO_NULL (1 << 2) @@ -123,6 +125,7 @@ static const struct xpad_device { u8 mapping; u8 xtype; } xpad_device[] = { + { 0x0079, 0x18d4, "GPD Win 2 Controller", 0, XTYPE_XBOX360 }, { 0x044f, 0x0f00, "Thrustmaster Wheel", 0, XTYPE_XBOX }, { 0x044f, 0x0f03, "Thrustmaster Wheel", 0, XTYPE_XBOX }, { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX }, @@ -387,15 +390,15 @@ static const signed short xpad_abs_triggers[] = { * match against vendor id as well. Wired Xbox 360 devices have protocol 1, * wireless controllers have protocol 129. */ -#define XPAD_XBOX360_VENDOR_PROTOCOL(vend,pr) \ +#define XPAD_XBOX360_VENDOR_PROTOCOL(vend, pr) \ .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO, \ .idVendor = (vend), \ .bInterfaceClass = USB_CLASS_VENDOR_SPEC, \ .bInterfaceSubClass = 93, \ .bInterfaceProtocol = (pr) #define XPAD_XBOX360_VENDOR(vend) \ - { XPAD_XBOX360_VENDOR_PROTOCOL(vend,1) }, \ - { XPAD_XBOX360_VENDOR_PROTOCOL(vend,129) } + { XPAD_XBOX360_VENDOR_PROTOCOL((vend), 1) }, \ + { XPAD_XBOX360_VENDOR_PROTOCOL((vend), 129) } /* The Xbox One controller uses subclass 71 and protocol 208. */ #define XPAD_XBOXONE_VENDOR_PROTOCOL(vend, pr) \ @@ -405,10 +408,11 @@ static const signed short xpad_abs_triggers[] = { .bInterfaceSubClass = 71, \ .bInterfaceProtocol = (pr) #define XPAD_XBOXONE_VENDOR(vend) \ - { XPAD_XBOXONE_VENDOR_PROTOCOL(vend, 208) } + { XPAD_XBOXONE_VENDOR_PROTOCOL((vend), 208) } static const struct usb_device_id xpad_table[] = { { USB_INTERFACE_INFO('X', 'B', 0) }, /* X-Box USB-IF not approved class */ + XPAD_XBOX360_VENDOR(0x0079), /* GPD Win 2 Controller */ XPAD_XBOX360_VENDOR(0x044f), /* Thrustmaster X-Box 360 controllers */ XPAD_XBOX360_VENDOR(0x045e), /* Microsoft X-Box 360 controllers */ XPAD_XBOXONE_VENDOR(0x045e), /* Microsoft X-Box One controllers */ @@ -1573,7 +1577,6 @@ static void xpad_close(struct input_dev *dev) static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs) { struct usb_xpad *xpad = input_get_drvdata(input_dev); - set_bit(abs, input_dev->absbit); switch (abs) { case ABS_X: @@ -1593,6 +1596,9 @@ static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs) case ABS_HAT0Y: /* the d-pad (only if dpad is mapped to axes */ input_set_abs_params(input_dev, abs, -1, 1, 0, 0); break; + default: + input_set_abs_params(input_dev, abs, 0, 0, 0, 0); + break; } } @@ -1633,10 +1639,7 @@ static int xpad_init_input(struct usb_xpad *xpad) input_dev->close = xpad_close; } - __set_bit(EV_KEY, input_dev->evbit); - if (!(xpad->mapping & MAP_STICKS_TO_NULL)) { - __set_bit(EV_ABS, input_dev->evbit); /* set up axes */ for (i = 0; xpad_abs[i] >= 0; i++) xpad_set_up_abs(input_dev, xpad_abs[i]); @@ -1644,21 +1647,22 @@ static int xpad_init_input(struct usb_xpad *xpad) /* set up standard buttons */ for (i = 0; xpad_common_btn[i] >= 0; i++) - __set_bit(xpad_common_btn[i], input_dev->keybit); + input_set_capability(input_dev, EV_KEY, xpad_common_btn[i]); /* set up model-specific ones */ if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX360W || xpad->xtype == XTYPE_XBOXONE) { for (i = 0; xpad360_btn[i] >= 0; i++) - __set_bit(xpad360_btn[i], input_dev->keybit); + input_set_capability(input_dev, EV_KEY, xpad360_btn[i]); } else { for (i = 0; xpad_btn[i] >= 0; i++) - __set_bit(xpad_btn[i], input_dev->keybit); + input_set_capability(input_dev, EV_KEY, xpad_btn[i]); } if (xpad->mapping & MAP_DPAD_TO_BUTTONS) { for (i = 0; xpad_btn_pad[i] >= 0; i++) - __set_bit(xpad_btn_pad[i], input_dev->keybit); + input_set_capability(input_dev, EV_KEY, + xpad_btn_pad[i]); } /* @@ -1675,7 +1679,8 @@ static int xpad_init_input(struct usb_xpad *xpad) if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) { for (i = 0; xpad_btn_triggers[i] >= 0; i++) - __set_bit(xpad_btn_triggers[i], input_dev->keybit); + input_set_capability(input_dev, EV_KEY, + xpad_btn_triggers[i]); } else { for (i = 0; xpad_abs_triggers[i] >= 0; i++) xpad_set_up_abs(input_dev, xpad_abs_triggers[i]); diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c index 79eb29550c34..489ddd37bd4e 100644 --- a/drivers/input/keyboard/cros_ec_keyb.c +++ b/drivers/input/keyboard/cros_ec_keyb.c @@ -244,24 +244,35 @@ static int cros_ec_keyb_work(struct notifier_block *nb, switch (ckdev->ec->event_data.event_type) { case EC_MKBP_EVENT_KEY_MATRIX: - /* - * If EC is not the wake source, discard key state changes - * during suspend. - */ - if (queued_during_suspend) - return NOTIFY_OK; + if (device_may_wakeup(ckdev->dev)) { + pm_wakeup_event(ckdev->dev, 0); + } else { + /* + * If keyboard is not wake enabled, discard key state + * changes during suspend. Switches will be re-checked + * in cros_ec_keyb_resume() to be sure nothing is lost. + */ + if (queued_during_suspend) + return NOTIFY_OK; + } if (ckdev->ec->event_size != ckdev->cols) { dev_err(ckdev->dev, "Discarded incomplete key matrix event.\n"); return NOTIFY_OK; } + cros_ec_keyb_process(ckdev, ckdev->ec->event_data.data.key_matrix, ckdev->ec->event_size); break; case EC_MKBP_EVENT_SYSRQ: + if (device_may_wakeup(ckdev->dev)) + pm_wakeup_event(ckdev->dev, 0); + else if (queued_during_suspend) + return NOTIFY_OK; + val = get_unaligned_le32(&ckdev->ec->event_data.data.sysrq); dev_dbg(ckdev->dev, "sysrq code from EC: %#x\n", val); handle_sysrq(val); @@ -269,12 +280,9 @@ static int cros_ec_keyb_work(struct notifier_block *nb, case EC_MKBP_EVENT_BUTTON: case EC_MKBP_EVENT_SWITCH: - /* - * If EC is not the wake source, discard key state - * changes during suspend. Switches will be re-checked in - * cros_ec_keyb_resume() to be sure nothing is lost. - */ - if (queued_during_suspend) + if (device_may_wakeup(ckdev->dev)) + pm_wakeup_event(ckdev->dev, 0); + else if (queued_during_suspend) return NOTIFY_OK; if (ckdev->ec->event_data.event_type == EC_MKBP_EVENT_BUTTON) { @@ -639,6 +647,7 @@ static int cros_ec_keyb_probe(struct platform_device *pdev) return err; } + device_init_wakeup(ckdev->dev, true); return 0; } diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c index ded5b84e336d..d8fd58fdf050 100644 --- a/drivers/input/misc/ati_remote2.c +++ b/drivers/input/misc/ati_remote2.c @@ -22,7 +22,7 @@ MODULE_LICENSE("GPL"); /* * ATI Remote Wonder II Channel Configuration * - * The remote control can by assigned one of sixteen "channels" in order to facilitate + * The remote control can be assigned one of sixteen "channels" in order to facilitate * the use of multiple remote controls within range of each other. * A remote's "channel" may be altered by pressing and holding the "PC" button for * approximately 3 seconds, after which the button will slowly flash the count of the diff --git a/drivers/input/misc/hp_sdc_rtc.c b/drivers/input/misc/hp_sdc_rtc.c index 49b34de0aed4..47eb8ca729fe 100644 --- a/drivers/input/misc/hp_sdc_rtc.c +++ b/drivers/input/misc/hp_sdc_rtc.c @@ -509,18 +509,6 @@ static int hp_sdc_rtc_proc_show(struct seq_file *m, void *v) #undef NY } -static int hp_sdc_rtc_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, hp_sdc_rtc_proc_show, NULL); -} - -static const struct file_operations hp_sdc_rtc_proc_fops = { - .open = hp_sdc_rtc_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static int hp_sdc_rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -713,7 +701,7 @@ static int __init hp_sdc_rtc_init(void) if (misc_register(&hp_sdc_rtc_dev) != 0) printk(KERN_INFO "Could not register misc. dev for i8042 rtc\n"); - proc_create("driver/rtc", 0, NULL, &hp_sdc_rtc_proc_fops); + proc_create_single("driver/rtc", 0, NULL, hp_sdc_rtc_proc_show); printk(KERN_INFO "HP i8042 SDC + MSM-58321 RTC support loaded " "(RTC v " RTC_VERSION ")\n"); diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index 89ebb8f39fee..f27f23f2d99a 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig @@ -133,6 +133,18 @@ config MOUSE_PS2_ELANTECH If unsure, say N. +config MOUSE_PS2_ELANTECH_SMBUS + bool "Elantech PS/2 SMbus companion" if EXPERT + default y + depends on MOUSE_PS2 && MOUSE_PS2_ELANTECH + depends on I2C=y || I2C=MOUSE_PS2 + select MOUSE_PS2_SMBUS + help + Say Y here if you have a Elantech touchpad connected to + to an SMBus, but enumerated through PS/2. + + If unsure, say Y. + config MOUSE_PS2_SENTELIC bool "Sentelic Finger Sensing Pad PS/2 protocol extension" depends on MOUSE_PS2 diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 38f9501acdf0..cb5579716dba 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -2049,14 +2049,11 @@ static int alps_hw_init_v1_v2(struct psmouse *psmouse) return 0; } -static int alps_hw_init_v6(struct psmouse *psmouse) +/* Must be in passthrough mode when calling this function */ +static int alps_trackstick_enter_extended_mode_v3_v6(struct psmouse *psmouse) { unsigned char param[2] = {0xC8, 0x14}; - /* Enter passthrough mode to let trackpoint enter 6byte raw mode */ - if (alps_passthrough_mode_v2(psmouse, true)) - return -1; - if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || @@ -2064,9 +2061,25 @@ static int alps_hw_init_v6(struct psmouse *psmouse) ps2_command(&psmouse->ps2dev, ¶m[1], PSMOUSE_CMD_SETRATE)) return -1; + return 0; +} + +static int alps_hw_init_v6(struct psmouse *psmouse) +{ + int ret; + + /* Enter passthrough mode to let trackpoint enter 6byte raw mode */ + if (alps_passthrough_mode_v2(psmouse, true)) + return -1; + + ret = alps_trackstick_enter_extended_mode_v3_v6(psmouse); + if (alps_passthrough_mode_v2(psmouse, false)) return -1; + if (ret) + return ret; + if (alps_absolute_mode_v6(psmouse)) { psmouse_err(psmouse, "Failed to enable absolute mode\n"); return -1; @@ -2140,10 +2153,18 @@ error: static int alps_setup_trackstick_v3(struct psmouse *psmouse, int reg_base) { - struct ps2dev *ps2dev = &psmouse->ps2dev; int ret = 0; + int reg_val; unsigned char param[4]; + /* + * We need to configure trackstick to report data for touchpad in + * extended format. And also we need to tell touchpad to expect data + * from trackstick in extended format. Without this configuration + * trackstick packets sent from touchpad are in basic format which is + * different from what we expect. + */ + if (alps_passthrough_mode_v3(psmouse, reg_base, true)) return -EIO; @@ -2161,39 +2182,36 @@ static int alps_setup_trackstick_v3(struct psmouse *psmouse, int reg_base) ret = -ENODEV; } else { psmouse_dbg(psmouse, "trackstick E7 report: %3ph\n", param); - - /* - * Not sure what this does, but it is absolutely - * essential. Without it, the touchpad does not - * work at all and the trackstick just emits normal - * PS/2 packets. - */ - if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || - ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || - ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || - alps_command_mode_send_nibble(psmouse, 0x9) || - alps_command_mode_send_nibble(psmouse, 0x4)) { - psmouse_err(psmouse, - "Error sending magic E6 sequence\n"); + if (alps_trackstick_enter_extended_mode_v3_v6(psmouse)) { + psmouse_err(psmouse, "Failed to enter into trackstick extended mode\n"); ret = -EIO; - goto error; } + } + + if (alps_passthrough_mode_v3(psmouse, reg_base, false)) + return -EIO; + + if (ret) + return ret; + if (alps_enter_command_mode(psmouse)) + return -EIO; + + reg_val = alps_command_mode_read_reg(psmouse, reg_base + 0x08); + if (reg_val == -1) { + ret = -EIO; + } else { /* - * This ensures the trackstick packets are in the format - * supported by this driver. If bit 1 isn't set the packet - * format is different. + * Tell touchpad that trackstick is now in extended mode. + * If bit 1 isn't set the packet format is different. */ - if (alps_enter_command_mode(psmouse) || - alps_command_mode_write_reg(psmouse, - reg_base + 0x08, 0x82) || - alps_exit_command_mode(psmouse)) + reg_val |= BIT(1); + if (__alps_command_mode_write_reg(psmouse, reg_val)) ret = -EIO; } -error: - if (alps_passthrough_mode_v3(psmouse, reg_base, false)) - ret = -EIO; + if (alps_exit_command_mode(psmouse)) + return -EIO; return ret; } diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index 75e757520ef0..8ff75114e762 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -36,6 +36,7 @@ #include <linux/jiffies.h> #include <linux/completion.h> #include <linux/of.h> +#include <linux/property.h> #include <linux/regulator/consumer.h> #include <asm/unaligned.h> @@ -51,6 +52,7 @@ #define ETP_MAX_FINGERS 5 #define ETP_FINGER_DATA_LEN 5 #define ETP_REPORT_ID 0x5D +#define ETP_TP_REPORT_ID 0x5E #define ETP_REPORT_ID_OFFSET 2 #define ETP_TOUCH_INFO_OFFSET 3 #define ETP_FINGER_DATA_OFFSET 4 @@ -61,6 +63,7 @@ struct elan_tp_data { struct i2c_client *client; struct input_dev *input; + struct input_dev *tp_input; /* trackpoint input node */ struct regulator *vcc; const struct elan_transport_ops *ops; @@ -930,6 +933,33 @@ static void elan_report_absolute(struct elan_tp_data *data, u8 *packet) input_sync(input); } +static void elan_report_trackpoint(struct elan_tp_data *data, u8 *report) +{ + struct input_dev *input = data->tp_input; + u8 *packet = &report[ETP_REPORT_ID_OFFSET + 1]; + int x, y; + + if (!data->tp_input) { + dev_warn_once(&data->client->dev, + "received a trackpoint report while no trackpoint device has been created. Please report upstream.\n"); + return; + } + + input_report_key(input, BTN_LEFT, packet[0] & 0x01); + input_report_key(input, BTN_RIGHT, packet[0] & 0x02); + input_report_key(input, BTN_MIDDLE, packet[0] & 0x04); + + if ((packet[3] & 0x0F) == 0x06) { + x = packet[4] - (int)((packet[1] ^ 0x80) << 1); + y = (int)((packet[2] ^ 0x80) << 1) - packet[5]; + + input_report_rel(input, REL_X, x); + input_report_rel(input, REL_Y, y); + } + + input_sync(input); +} + static irqreturn_t elan_isr(int irq, void *dev_id) { struct elan_tp_data *data = dev_id; @@ -951,11 +981,17 @@ static irqreturn_t elan_isr(int irq, void *dev_id) if (error) goto out; - if (report[ETP_REPORT_ID_OFFSET] != ETP_REPORT_ID) + switch (report[ETP_REPORT_ID_OFFSET]) { + case ETP_REPORT_ID: + elan_report_absolute(data, report); + break; + case ETP_TP_REPORT_ID: + elan_report_trackpoint(data, report); + break; + default: dev_err(dev, "invalid report id data (%x)\n", report[ETP_REPORT_ID_OFFSET]); - else - elan_report_absolute(data, report); + } out: return IRQ_HANDLED; @@ -966,6 +1002,36 @@ out: * Elan initialization functions ****************************************************************** */ + +static int elan_setup_trackpoint_input_device(struct elan_tp_data *data) +{ + struct device *dev = &data->client->dev; + struct input_dev *input; + + input = devm_input_allocate_device(dev); + if (!input) + return -ENOMEM; + + input->name = "Elan TrackPoint"; + input->id.bustype = BUS_I2C; + input->id.vendor = ELAN_VENDOR_ID; + input->id.product = data->product_id; + input_set_drvdata(input, data); + + input_set_capability(input, EV_REL, REL_X); + input_set_capability(input, EV_REL, REL_Y); + input_set_capability(input, EV_KEY, BTN_LEFT); + input_set_capability(input, EV_KEY, BTN_RIGHT); + input_set_capability(input, EV_KEY, BTN_MIDDLE); + + __set_bit(INPUT_PROP_POINTER, input->propbit); + __set_bit(INPUT_PROP_POINTING_STICK, input->propbit); + + data->tp_input = input; + + return 0; +} + static int elan_setup_input_device(struct elan_tp_data *data) { struct device *dev = &data->client->dev; @@ -1140,6 +1206,12 @@ static int elan_probe(struct i2c_client *client, if (error) return error; + if (device_property_read_bool(&client->dev, "elan,trackpoint")) { + error = elan_setup_trackpoint_input_device(data); + if (error) + return error; + } + /* * Platform code (ACPI, DTS) should normally set up interrupt * for us, but in case it did not let's fall back to using falling @@ -1177,6 +1249,16 @@ static int elan_probe(struct i2c_client *client, return error; } + if (data->tp_input) { + error = input_register_device(data->tp_input); + if (error) { + dev_err(&client->dev, + "failed to register TrackPoint input device: %d\n", + error); + return error; + } + } + /* * Systems using device tree should set up wakeup via DTS, * the rest will configure device as wakeup source by default. @@ -1262,6 +1344,7 @@ static const struct acpi_device_id elan_acpi_id[] = { { "ELAN060B", 0 }, { "ELAN060C", 0 }, { "ELAN0611", 0 }, + { "ELAN0612", 0 }, { "ELAN1000", 0 }, { } }; diff --git a/drivers/input/mouse/elan_i2c_smbus.c b/drivers/input/mouse/elan_i2c_smbus.c index 29f99529b187..cfcb32559925 100644 --- a/drivers/input/mouse/elan_i2c_smbus.c +++ b/drivers/input/mouse/elan_i2c_smbus.c @@ -130,7 +130,7 @@ static int elan_smbus_get_baseline_data(struct i2c_client *client, bool max_baseline, u8 *value) { int error; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; error = i2c_smbus_read_block_data(client, max_baseline ? @@ -149,7 +149,7 @@ static int elan_smbus_get_version(struct i2c_client *client, bool iap, u8 *version) { int error; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; error = i2c_smbus_read_block_data(client, iap ? ETP_SMBUS_IAP_VERSION_CMD : @@ -170,7 +170,7 @@ static int elan_smbus_get_sm_version(struct i2c_client *client, u8 *clickpad) { int error; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; error = i2c_smbus_read_block_data(client, ETP_SMBUS_SM_VERSION_CMD, val); @@ -188,7 +188,7 @@ static int elan_smbus_get_sm_version(struct i2c_client *client, static int elan_smbus_get_product_id(struct i2c_client *client, u16 *id) { int error; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; error = i2c_smbus_read_block_data(client, ETP_SMBUS_UNIQUEID_CMD, val); @@ -205,7 +205,7 @@ static int elan_smbus_get_checksum(struct i2c_client *client, bool iap, u16 *csum) { int error; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; error = i2c_smbus_read_block_data(client, iap ? ETP_SMBUS_FW_CHECKSUM_CMD : @@ -226,7 +226,7 @@ static int elan_smbus_get_max(struct i2c_client *client, { int ret; int error; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; ret = i2c_smbus_read_block_data(client, ETP_SMBUS_RANGE_CMD, val); if (ret != 3) { @@ -246,7 +246,7 @@ static int elan_smbus_get_resolution(struct i2c_client *client, { int ret; int error; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; ret = i2c_smbus_read_block_data(client, ETP_SMBUS_RESOLUTION_CMD, val); if (ret != 3) { @@ -267,7 +267,7 @@ static int elan_smbus_get_num_traces(struct i2c_client *client, { int ret; int error; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; ret = i2c_smbus_read_block_data(client, ETP_SMBUS_XY_TRACENUM_CMD, val); if (ret != 3) { @@ -294,7 +294,7 @@ static int elan_smbus_iap_get_mode(struct i2c_client *client, { int error; u16 constant; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; error = i2c_smbus_read_block_data(client, ETP_SMBUS_IAP_CTRL_CMD, val); if (error < 0) { @@ -345,7 +345,7 @@ static int elan_smbus_prepare_fw_update(struct i2c_client *client) int len; int error; enum tp_mode mode; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; u8 cmd[4] = {0x0F, 0x78, 0x00, 0x06}; u16 password; @@ -419,7 +419,7 @@ static int elan_smbus_write_fw_block(struct i2c_client *client, struct device *dev = &client->dev; int error; u16 result; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; /* * Due to the limitation of smbus protocol limiting diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index db47a5e1d114..fb4d902c4403 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -14,17 +14,20 @@ #include <linux/dmi.h> #include <linux/slab.h> #include <linux/module.h> +#include <linux/i2c.h> #include <linux/input.h> #include <linux/input/mt.h> +#include <linux/platform_device.h> #include <linux/serio.h> #include <linux/libps2.h> #include <asm/unaligned.h> #include "psmouse.h" #include "elantech.h" +#include "elan_i2c.h" #define elantech_debug(fmt, ...) \ do { \ - if (etd->debug) \ + if (etd->info.debug) \ psmouse_printk(KERN_DEBUG, psmouse, \ fmt, ##__VA_ARGS__); \ } while (0) @@ -105,7 +108,7 @@ static int elantech_read_reg(struct psmouse *psmouse, unsigned char reg, if (reg > 0x11 && reg < 0x20) return -1; - switch (etd->hw_version) { + switch (etd->info.hw_version) { case 1: if (ps2_sliced_command(&psmouse->ps2dev, ETP_REGISTER_READ) || ps2_sliced_command(&psmouse->ps2dev, reg) || @@ -137,7 +140,7 @@ static int elantech_read_reg(struct psmouse *psmouse, unsigned char reg, if (rc) psmouse_err(psmouse, "failed to read register 0x%02x.\n", reg); - else if (etd->hw_version != 4) + else if (etd->info.hw_version != 4) *val = param[0]; else *val = param[1]; @@ -160,7 +163,7 @@ static int elantech_write_reg(struct psmouse *psmouse, unsigned char reg, if (reg > 0x11 && reg < 0x20) return -1; - switch (etd->hw_version) { + switch (etd->info.hw_version) { case 1: if (ps2_sliced_command(&psmouse->ps2dev, ETP_REGISTER_WRITE) || ps2_sliced_command(&psmouse->ps2dev, reg) || @@ -237,7 +240,7 @@ static void elantech_report_absolute_v1(struct psmouse *psmouse) unsigned char *packet = psmouse->packet; int fingers; - if (etd->fw_version < 0x020000) { + if (etd->info.fw_version < 0x020000) { /* * byte 0: D U p1 p2 1 p3 R L * byte 1: f 0 th tw x9 x8 y9 y8 @@ -252,7 +255,7 @@ static void elantech_report_absolute_v1(struct psmouse *psmouse) fingers = (packet[0] & 0xc0) >> 6; } - if (etd->jumpy_cursor) { + if (etd->info.jumpy_cursor) { if (fingers != 1) { etd->single_finger_reports = 0; } else if (etd->single_finger_reports < 2) { @@ -282,8 +285,8 @@ static void elantech_report_absolute_v1(struct psmouse *psmouse) psmouse_report_standard_buttons(dev, packet[0]); - if (etd->fw_version < 0x020000 && - (etd->capabilities[0] & ETP_CAP_HAS_ROCKER)) { + if (etd->info.fw_version < 0x020000 && + (etd->info.capabilities[0] & ETP_CAP_HAS_ROCKER)) { /* rocker up */ input_report_key(dev, BTN_FORWARD, packet[0] & 0x40); /* rocker down */ @@ -391,7 +394,7 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse) input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3); input_report_key(dev, BTN_TOOL_QUADTAP, fingers == 4); psmouse_report_standard_buttons(dev, packet[0]); - if (etd->reports_pressure) { + if (etd->info.reports_pressure) { input_report_abs(dev, ABS_PRESSURE, pres); input_report_abs(dev, ABS_TOOL_WIDTH, width); } @@ -444,7 +447,7 @@ static void elantech_report_trackpoint(struct psmouse *psmouse, default: /* Dump unexpected packet sequences if debug=1 (default) */ - if (etd->debug == 1) + if (etd->info.debug == 1) elantech_packet_dump(psmouse); break; @@ -523,7 +526,7 @@ static void elantech_report_absolute_v3(struct psmouse *psmouse, input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3); /* For clickpads map both buttons to BTN_LEFT */ - if (etd->fw_version & 0x001000) + if (etd->info.fw_version & 0x001000) input_report_key(dev, BTN_LEFT, packet[0] & 0x03); else psmouse_report_standard_buttons(dev, packet[0]); @@ -541,7 +544,7 @@ static void elantech_input_sync_v4(struct psmouse *psmouse) unsigned char *packet = psmouse->packet; /* For clickpads map both buttons to BTN_LEFT */ - if (etd->fw_version & 0x001000) + if (etd->info.fw_version & 0x001000) input_report_key(dev, BTN_LEFT, packet[0] & 0x03); else psmouse_report_standard_buttons(dev, packet[0]); @@ -669,7 +672,7 @@ static int elantech_packet_check_v1(struct psmouse *psmouse) unsigned char p1, p2, p3; /* Parity bits are placed differently */ - if (etd->fw_version < 0x020000) { + if (etd->info.fw_version < 0x020000) { /* byte 0: D U p1 p2 1 p3 R L */ p1 = (packet[0] & 0x20) >> 5; p2 = (packet[0] & 0x10) >> 4; @@ -714,7 +717,7 @@ static int elantech_packet_check_v2(struct psmouse *psmouse) * With all three cases, if the constant bits are not exactly what I * expected, I consider them invalid. */ - if (etd->reports_pressure) + if (etd->info.reports_pressure) return (packet[0] & 0x0c) == 0x04 && (packet[3] & 0x0f) == 0x02; @@ -751,7 +754,7 @@ static int elantech_packet_check_v3(struct psmouse *psmouse) * If the hardware flag 'crc_enabled' is set the packets have * different signatures. */ - if (etd->crc_enabled) { + if (etd->info.crc_enabled) { if ((packet[3] & 0x09) == 0x08) return PACKET_V3_HEAD; @@ -782,7 +785,7 @@ static int elantech_packet_check_v4(struct psmouse *psmouse) return PACKET_TRACKPOINT; /* This represents the version of IC body. */ - ic_version = (etd->fw_version & 0x0f0000) >> 16; + ic_version = (etd->info.fw_version & 0x0f0000) >> 16; /* * Sanity check based on the constant bits of a packet. @@ -791,9 +794,9 @@ static int elantech_packet_check_v4(struct psmouse *psmouse) * the IC body, but are the same for every packet, * regardless of the type. */ - if (etd->crc_enabled) + if (etd->info.crc_enabled) sanity_check = ((packet[3] & 0x08) == 0x00); - else if (ic_version == 7 && etd->samples[1] == 0x2A) + else if (ic_version == 7 && etd->info.samples[1] == 0x2A) sanity_check = ((packet[3] & 0x1c) == 0x10); else sanity_check = ((packet[0] & 0x0c) == 0x04 && @@ -827,12 +830,12 @@ static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse) if (psmouse->pktcnt < psmouse->pktsize) return PSMOUSE_GOOD_DATA; - if (etd->debug > 1) + if (etd->info.debug > 1) elantech_packet_dump(psmouse); - switch (etd->hw_version) { + switch (etd->info.hw_version) { case 1: - if (etd->paritycheck && !elantech_packet_check_v1(psmouse)) + if (etd->info.paritycheck && !elantech_packet_check_v1(psmouse)) return PSMOUSE_BAD_DATA; elantech_report_absolute_v1(psmouse); @@ -843,7 +846,7 @@ static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse) if (elantech_debounce_check_v2(psmouse)) return PSMOUSE_FULL_PACKET; - if (etd->paritycheck && !elantech_packet_check_v2(psmouse)) + if (etd->info.paritycheck && !elantech_packet_check_v2(psmouse)) return PSMOUSE_BAD_DATA; elantech_report_absolute_v2(psmouse); @@ -916,7 +919,7 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse) int tries = ETP_READ_BACK_TRIES; int rc = 0; - switch (etd->hw_version) { + switch (etd->info.hw_version) { case 1: etd->reg_10 = 0x16; etd->reg_11 = 0x8f; @@ -939,7 +942,7 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse) break; case 3: - if (etd->set_hw_resolution) + if (etd->info.set_hw_resolution) etd->reg_10 = 0x0b; else etd->reg_10 = 0x01; @@ -976,7 +979,7 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse) if (rc) { psmouse_err(psmouse, "failed to read back register 0x10.\n"); - } else if (etd->hw_version == 1 && + } else if (etd->info.hw_version == 1 && !(val & ETP_R10_ABSOLUTE_MODE)) { psmouse_err(psmouse, "touchpad refuses to switch to absolute mode.\n"); @@ -997,10 +1000,11 @@ static int elantech_set_range(struct psmouse *psmouse, unsigned int *width) { struct elantech_data *etd = psmouse->private; + struct elantech_device_info *info = &etd->info; unsigned char param[3]; unsigned char traces; - switch (etd->hw_version) { + switch (info->hw_version) { case 1: *x_min = ETP_XMIN_V1; *y_min = ETP_YMIN_V1; @@ -1009,9 +1013,9 @@ static int elantech_set_range(struct psmouse *psmouse, break; case 2: - if (etd->fw_version == 0x020800 || - etd->fw_version == 0x020b00 || - etd->fw_version == 0x020030) { + if (info->fw_version == 0x020800 || + info->fw_version == 0x020b00 || + info->fw_version == 0x020030) { *x_min = ETP_XMIN_V2; *y_min = ETP_YMIN_V2; *x_max = ETP_XMAX_V2; @@ -1020,35 +1024,35 @@ static int elantech_set_range(struct psmouse *psmouse, int i; int fixed_dpi; - i = (etd->fw_version > 0x020800 && - etd->fw_version < 0x020900) ? 1 : 2; + i = (info->fw_version > 0x020800 && + info->fw_version < 0x020900) ? 1 : 2; - if (etd->send_cmd(psmouse, ETP_FW_ID_QUERY, param)) + if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param)) return -1; fixed_dpi = param[1] & 0x10; - if (((etd->fw_version >> 16) == 0x14) && fixed_dpi) { - if (etd->send_cmd(psmouse, ETP_SAMPLE_QUERY, param)) + if (((info->fw_version >> 16) == 0x14) && fixed_dpi) { + if (info->send_cmd(psmouse, ETP_SAMPLE_QUERY, param)) return -1; - *x_max = (etd->capabilities[1] - i) * param[1] / 2; - *y_max = (etd->capabilities[2] - i) * param[2] / 2; - } else if (etd->fw_version == 0x040216) { + *x_max = (info->capabilities[1] - i) * param[1] / 2; + *y_max = (info->capabilities[2] - i) * param[2] / 2; + } else if (info->fw_version == 0x040216) { *x_max = 819; *y_max = 405; - } else if (etd->fw_version == 0x040219 || etd->fw_version == 0x040215) { + } else if (info->fw_version == 0x040219 || info->fw_version == 0x040215) { *x_max = 900; *y_max = 500; } else { - *x_max = (etd->capabilities[1] - i) * 64; - *y_max = (etd->capabilities[2] - i) * 64; + *x_max = (info->capabilities[1] - i) * 64; + *y_max = (info->capabilities[2] - i) * 64; } } break; case 3: - if (etd->send_cmd(psmouse, ETP_FW_ID_QUERY, param)) + if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param)) return -1; *x_max = (0x0f & param[0]) << 8 | param[1]; @@ -1056,12 +1060,12 @@ static int elantech_set_range(struct psmouse *psmouse, break; case 4: - if (etd->send_cmd(psmouse, ETP_FW_ID_QUERY, param)) + if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param)) return -1; *x_max = (0x0f & param[0]) << 8 | param[1]; *y_max = (0xf0 & param[0]) << 4 | param[2]; - traces = etd->capabilities[1]; + traces = info->capabilities[1]; if ((traces < 2) || (traces > *x_max)) return -1; @@ -1083,7 +1087,8 @@ static unsigned int elantech_convert_res(unsigned int val) static int elantech_get_resolution_v4(struct psmouse *psmouse, unsigned int *x_res, - unsigned int *y_res) + unsigned int *y_res, + unsigned int *bus) { unsigned char param[3]; @@ -1092,6 +1097,7 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse, *x_res = elantech_convert_res(param[1] & 0x0f); *y_res = elantech_convert_res((param[1] & 0xf0) >> 4); + *bus = param[2]; return 0; } @@ -1140,7 +1146,7 @@ static void elantech_set_buttonpad_prop(struct psmouse *psmouse) struct input_dev *dev = psmouse->dev; struct elantech_data *etd = psmouse->private; - if (etd->fw_version & 0x001000) { + if (etd->info.fw_version & 0x001000) { __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit); __clear_bit(BTN_RIGHT, dev->keybit); } @@ -1176,8 +1182,8 @@ static int elantech_set_input_params(struct psmouse *psmouse) { struct input_dev *dev = psmouse->dev; struct elantech_data *etd = psmouse->private; + struct elantech_device_info *info = &etd->info; unsigned int x_min = 0, y_min = 0, x_max = 0, y_max = 0, width = 0; - unsigned int x_res = 31, y_res = 31; if (elantech_set_range(psmouse, &x_min, &y_min, &x_max, &y_max, &width)) return -1; @@ -1197,11 +1203,11 @@ static int elantech_set_input_params(struct psmouse *psmouse) __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); __set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); - switch (etd->hw_version) { + switch (info->hw_version) { case 1: /* Rocker button */ - if (etd->fw_version < 0x020000 && - (etd->capabilities[0] & ETP_CAP_HAS_ROCKER)) { + if (info->fw_version < 0x020000 && + (info->capabilities[0] & ETP_CAP_HAS_ROCKER)) { __set_bit(BTN_FORWARD, dev->keybit); __set_bit(BTN_BACK, dev->keybit); } @@ -1214,11 +1220,11 @@ static int elantech_set_input_params(struct psmouse *psmouse) __set_bit(INPUT_PROP_SEMI_MT, dev->propbit); /* fall through */ case 3: - if (etd->hw_version == 3) + if (info->hw_version == 3) elantech_set_buttonpad_prop(psmouse); input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0); input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0); - if (etd->reports_pressure) { + if (info->reports_pressure) { input_set_abs_params(dev, ABS_PRESSURE, ETP_PMIN_V2, ETP_PMAX_V2, 0, 0); input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2, @@ -1230,13 +1236,6 @@ static int elantech_set_input_params(struct psmouse *psmouse) break; case 4: - if (elantech_get_resolution_v4(psmouse, &x_res, &y_res)) { - /* - * if query failed, print a warning and leave the values - * zero to resemble synaptics.c behavior. - */ - psmouse_warn(psmouse, "couldn't query resolution data.\n"); - } elantech_set_buttonpad_prop(psmouse); __set_bit(BTN_TOOL_QUADTAP, dev->keybit); /* For X to recognize me as touchpad. */ @@ -1265,11 +1264,11 @@ static int elantech_set_input_params(struct psmouse *psmouse) break; } - input_abs_set_res(dev, ABS_X, x_res); - input_abs_set_res(dev, ABS_Y, y_res); - if (etd->hw_version > 1) { - input_abs_set_res(dev, ABS_MT_POSITION_X, x_res); - input_abs_set_res(dev, ABS_MT_POSITION_Y, y_res); + input_abs_set_res(dev, ABS_X, info->x_res); + input_abs_set_res(dev, ABS_Y, info->y_res); + if (info->hw_version > 1) { + input_abs_set_res(dev, ABS_MT_POSITION_X, info->x_res); + input_abs_set_res(dev, ABS_MT_POSITION_Y, info->y_res); } etd->y_max = y_max; @@ -1317,7 +1316,7 @@ static ssize_t elantech_set_int_attr(struct psmouse *psmouse, return err; /* Do we need to preserve some bits for version 2 hardware too? */ - if (etd->hw_version == 1) { + if (etd->info.hw_version == 1) { if (attr->reg == 0x10) /* Force absolute mode always on */ value |= ETP_R10_ABSOLUTE_MODE; @@ -1337,11 +1336,22 @@ static ssize_t elantech_set_int_attr(struct psmouse *psmouse, .field_offset = offsetof(struct elantech_data, _name), \ .reg = _register, \ }; \ - PSMOUSE_DEFINE_ATTR(_name, S_IWUSR | S_IRUGO, \ + PSMOUSE_DEFINE_ATTR(_name, 0644, \ &elantech_attr_##_name, \ elantech_show_int_attr, \ elantech_set_int_attr) +#define ELANTECH_INFO_ATTR(_name) \ + static struct elantech_attr_data elantech_attr_##_name = { \ + .field_offset = offsetof(struct elantech_data, info) + \ + offsetof(struct elantech_device_info, _name), \ + .reg = 0, \ + }; \ + PSMOUSE_DEFINE_ATTR(_name, 0644, \ + &elantech_attr_##_name, \ + elantech_show_int_attr, \ + elantech_set_int_attr) + ELANTECH_INT_ATTR(reg_07, 0x07); ELANTECH_INT_ATTR(reg_10, 0x10); ELANTECH_INT_ATTR(reg_11, 0x11); @@ -1352,9 +1362,9 @@ ELANTECH_INT_ATTR(reg_23, 0x23); ELANTECH_INT_ATTR(reg_24, 0x24); ELANTECH_INT_ATTR(reg_25, 0x25); ELANTECH_INT_ATTR(reg_26, 0x26); -ELANTECH_INT_ATTR(debug, 0); -ELANTECH_INT_ATTR(paritycheck, 0); -ELANTECH_INT_ATTR(crc_enabled, 0); +ELANTECH_INFO_ATTR(debug); +ELANTECH_INFO_ATTR(paritycheck); +ELANTECH_INFO_ATTR(crc_enabled); static struct attribute *elantech_attrs[] = { &psmouse_attr_reg_07.dattr.attr, @@ -1469,6 +1479,12 @@ static void elantech_disconnect(struct psmouse *psmouse) { struct elantech_data *etd = psmouse->private; + /* + * We might have left a breadcrumb when trying to + * set up SMbus companion. + */ + psmouse_smbus_cleanup(psmouse); + if (etd->tp_dev) input_unregister_device(etd->tp_dev); sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj, @@ -1588,25 +1604,25 @@ static const struct dmi_system_id no_hw_res_dmi_table[] = { /* * determine hardware version and set some properties according to it. */ -static int elantech_set_properties(struct elantech_data *etd) +static int elantech_set_properties(struct elantech_device_info *info) { /* This represents the version of IC body. */ - int ver = (etd->fw_version & 0x0f0000) >> 16; + int ver = (info->fw_version & 0x0f0000) >> 16; /* Early version of Elan touchpads doesn't obey the rule. */ - if (etd->fw_version < 0x020030 || etd->fw_version == 0x020600) - etd->hw_version = 1; + if (info->fw_version < 0x020030 || info->fw_version == 0x020600) + info->hw_version = 1; else { switch (ver) { case 2: case 4: - etd->hw_version = 2; + info->hw_version = 2; break; case 5: - etd->hw_version = 3; + info->hw_version = 3; break; case 6 ... 15: - etd->hw_version = 4; + info->hw_version = 4; break; default: return -1; @@ -1614,100 +1630,88 @@ static int elantech_set_properties(struct elantech_data *etd) } /* decide which send_cmd we're gonna use early */ - etd->send_cmd = etd->hw_version >= 3 ? elantech_send_cmd : - synaptics_send_cmd; + info->send_cmd = info->hw_version >= 3 ? elantech_send_cmd : + synaptics_send_cmd; /* Turn on packet checking by default */ - etd->paritycheck = 1; + info->paritycheck = 1; /* * This firmware suffers from misreporting coordinates when * a touch action starts causing the mouse cursor or scrolled page * to jump. Enable a workaround. */ - etd->jumpy_cursor = - (etd->fw_version == 0x020022 || etd->fw_version == 0x020600); + info->jumpy_cursor = + (info->fw_version == 0x020022 || info->fw_version == 0x020600); - if (etd->hw_version > 1) { + if (info->hw_version > 1) { /* For now show extra debug information */ - etd->debug = 1; + info->debug = 1; - if (etd->fw_version >= 0x020800) - etd->reports_pressure = true; + if (info->fw_version >= 0x020800) + info->reports_pressure = true; } /* * The signatures of v3 and v4 packets change depending on the * value of this hardware flag. */ - etd->crc_enabled = (etd->fw_version & 0x4000) == 0x4000 || - dmi_check_system(elantech_dmi_force_crc_enabled); + info->crc_enabled = (info->fw_version & 0x4000) == 0x4000 || + dmi_check_system(elantech_dmi_force_crc_enabled); /* Enable real hardware resolution on hw_version 3 ? */ - etd->set_hw_resolution = !dmi_check_system(no_hw_res_dmi_table); + info->set_hw_resolution = !dmi_check_system(no_hw_res_dmi_table); return 0; } -/* - * Initialize the touchpad and create sysfs entries - */ -int elantech_init(struct psmouse *psmouse) +static int elantech_query_info(struct psmouse *psmouse, + struct elantech_device_info *info) { - struct elantech_data *etd; - int i; - int error = -EINVAL; unsigned char param[3]; - struct input_dev *tp_dev; - psmouse->private = etd = kzalloc(sizeof(struct elantech_data), GFP_KERNEL); - if (!etd) - return -ENOMEM; - - psmouse_reset(psmouse); - - etd->parity[0] = 1; - for (i = 1; i < 256; i++) - etd->parity[i] = etd->parity[i & (i - 1)] ^ 1; + memset(info, 0, sizeof(*info)); /* * Do the version query again so we can store the result */ if (synaptics_send_cmd(psmouse, ETP_FW_VERSION_QUERY, param)) { psmouse_err(psmouse, "failed to query firmware version.\n"); - goto init_fail; + return -EINVAL; } - etd->fw_version = (param[0] << 16) | (param[1] << 8) | param[2]; + info->fw_version = (param[0] << 16) | (param[1] << 8) | param[2]; - if (elantech_set_properties(etd)) { + if (elantech_set_properties(info)) { psmouse_err(psmouse, "unknown hardware version, aborting...\n"); - goto init_fail; + return -EINVAL; } psmouse_info(psmouse, "assuming hardware version %d (with firmware version 0x%02x%02x%02x)\n", - etd->hw_version, param[0], param[1], param[2]); + info->hw_version, param[0], param[1], param[2]); - if (etd->send_cmd(psmouse, ETP_CAPABILITIES_QUERY, - etd->capabilities)) { + if (info->send_cmd(psmouse, ETP_CAPABILITIES_QUERY, + info->capabilities)) { psmouse_err(psmouse, "failed to query capabilities.\n"); - goto init_fail; + return -EINVAL; } psmouse_info(psmouse, "Synaptics capabilities query result 0x%02x, 0x%02x, 0x%02x.\n", - etd->capabilities[0], etd->capabilities[1], - etd->capabilities[2]); + info->capabilities[0], info->capabilities[1], + info->capabilities[2]); - if (etd->hw_version != 1) { - if (etd->send_cmd(psmouse, ETP_SAMPLE_QUERY, etd->samples)) { + if (info->hw_version != 1) { + if (info->send_cmd(psmouse, ETP_SAMPLE_QUERY, info->samples)) { psmouse_err(psmouse, "failed to query sample data\n"); - goto init_fail; + return -EINVAL; } psmouse_info(psmouse, "Elan sample query result %02x, %02x, %02x\n", - etd->samples[0], etd->samples[1], etd->samples[2]); + info->samples[0], + info->samples[1], + info->samples[2]); } - if (etd->samples[1] == 0x74 && etd->hw_version == 0x03) { + if (info->samples[1] == 0x74 && info->hw_version == 0x03) { /* * This module has a bug which makes absolute mode * unusable, so let's abort so we'll be using standard @@ -1715,16 +1719,181 @@ int elantech_init(struct psmouse *psmouse) */ psmouse_info(psmouse, "absolute mode broken, forcing standard PS/2 protocol\n"); + return -ENODEV; + } + + /* The MSB indicates the presence of the trackpoint */ + info->has_trackpoint = (info->capabilities[0] & 0x80) == 0x80; + + info->x_res = 31; + info->y_res = 31; + if (info->hw_version == 4) { + if (elantech_get_resolution_v4(psmouse, + &info->x_res, + &info->y_res, + &info->bus)) { + psmouse_warn(psmouse, + "failed to query resolution data.\n"); + } + } + + return 0; +} + +#if defined(CONFIG_MOUSE_PS2_ELANTECH_SMBUS) + +/* + * The newest Elantech device can use a secondary bus (over SMBus) which + * provides a better bandwidth and allow a better control of the touchpads. + * This is used to decide if we need to use this bus or not. + */ +enum { + ELANTECH_SMBUS_NOT_SET = -1, + ELANTECH_SMBUS_OFF, + ELANTECH_SMBUS_ON, +}; + +static int elantech_smbus = IS_ENABLED(CONFIG_MOUSE_ELAN_I2C_SMBUS) ? + ELANTECH_SMBUS_NOT_SET : ELANTECH_SMBUS_OFF; +module_param_named(elantech_smbus, elantech_smbus, int, 0644); +MODULE_PARM_DESC(elantech_smbus, "Use a secondary bus for the Elantech device."); + +static int elantech_create_smbus(struct psmouse *psmouse, + struct elantech_device_info *info, + bool leave_breadcrumbs) +{ + const struct property_entry i2c_properties[] = { + PROPERTY_ENTRY_BOOL("elan,trackpoint"), + { }, + }; + struct i2c_board_info smbus_board = { + I2C_BOARD_INFO("elan_i2c", 0x15), + .flags = I2C_CLIENT_HOST_NOTIFY, + }; + + if (info->has_trackpoint) + smbus_board.properties = i2c_properties; + + return psmouse_smbus_init(psmouse, &smbus_board, NULL, 0, false, + leave_breadcrumbs); +} + +/** + * elantech_setup_smbus - called once the PS/2 devices are enumerated + * and decides to instantiate a SMBus InterTouch device. + */ +static int elantech_setup_smbus(struct psmouse *psmouse, + struct elantech_device_info *info, + bool leave_breadcrumbs) +{ + int error; + + if (elantech_smbus == ELANTECH_SMBUS_OFF) + return -ENXIO; + + if (elantech_smbus == ELANTECH_SMBUS_NOT_SET) { + /* + * New ICs are enabled by default. + * Old ICs are up to the user to decide. + */ + if (!ETP_NEW_IC_SMBUS_HOST_NOTIFY(info->fw_version)) + return -ENXIO; + } + + psmouse_info(psmouse, "Trying to set up SMBus access\n"); + + error = elantech_create_smbus(psmouse, info, leave_breadcrumbs); + if (error) { + if (error == -EAGAIN) + psmouse_info(psmouse, "SMbus companion is not ready yet\n"); + else + psmouse_err(psmouse, "unable to create intertouch device\n"); + + return error; + } + + return 0; +} + +static bool elantech_use_host_notify(struct psmouse *psmouse, + struct elantech_device_info *info) +{ + if (ETP_NEW_IC_SMBUS_HOST_NOTIFY(info->fw_version)) + return true; + + switch (info->bus) { + case ETP_BUS_PS2_ONLY: + /* expected case */ + break; + case ETP_BUS_SMB_ALERT_ONLY: + /* fall-through */ + case ETP_BUS_PS2_SMB_ALERT: + psmouse_dbg(psmouse, "Ignoring SMBus provider through alert protocol.\n"); + break; + case ETP_BUS_SMB_HST_NTFY_ONLY: + /* fall-through */ + case ETP_BUS_PS2_SMB_HST_NTFY: + return true; + default: + psmouse_dbg(psmouse, + "Ignoring SMBus bus provider %d.\n", + info->bus); + } + + return false; +} + +int elantech_init_smbus(struct psmouse *psmouse) +{ + struct elantech_device_info info; + int error = -EINVAL; + + psmouse_reset(psmouse); + + error = elantech_query_info(psmouse, &info); + if (error) + goto init_fail; + + if (info.hw_version < 4) { + error = -ENXIO; goto init_fail; } + return elantech_create_smbus(psmouse, &info, false); + init_fail: + psmouse_reset(psmouse); + return error; +} +#endif /* CONFIG_MOUSE_PS2_ELANTECH_SMBUS */ + +/* + * Initialize the touchpad and create sysfs entries + */ +static int elantech_setup_ps2(struct psmouse *psmouse, + struct elantech_device_info *info) +{ + struct elantech_data *etd; + int i; + int error = -EINVAL; + struct input_dev *tp_dev; + + psmouse->private = etd = kzalloc(sizeof(*etd), GFP_KERNEL); + if (!etd) + return -ENOMEM; + + etd->info = *info; + + etd->parity[0] = 1; + for (i = 1; i < 256; i++) + etd->parity[i] = etd->parity[i & (i - 1)] ^ 1; + if (elantech_set_absolute_mode(psmouse)) { psmouse_err(psmouse, "failed to put touchpad into absolute mode.\n"); goto init_fail; } - if (etd->fw_version == 0x381f17) { + if (info->fw_version == 0x381f17) { etd->original_set_rate = psmouse->set_rate; psmouse->set_rate = elantech_set_rate_restore_reg_07; } @@ -1743,8 +1912,7 @@ int elantech_init(struct psmouse *psmouse) goto init_fail; } - /* The MSB indicates the presence of the trackpoint */ - if ((etd->capabilities[0] & 0x80) == 0x80) { + if (info->has_trackpoint) { tp_dev = input_allocate_device(); if (!tp_dev) { @@ -1780,7 +1948,7 @@ int elantech_init(struct psmouse *psmouse) psmouse->protocol_handler = elantech_process_byte; psmouse->disconnect = elantech_disconnect; psmouse->reconnect = elantech_reconnect; - psmouse->pktsize = etd->hw_version > 1 ? 6 : 4; + psmouse->pktsize = info->hw_version > 1 ? 6 : 4; return 0; init_fail_tp_reg: @@ -1789,7 +1957,70 @@ int elantech_init(struct psmouse *psmouse) sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj, &elantech_attr_group); init_fail: - psmouse_reset(psmouse); kfree(etd); return error; } + +int elantech_init_ps2(struct psmouse *psmouse) +{ + struct elantech_device_info info; + int error = -EINVAL; + + psmouse_reset(psmouse); + + error = elantech_query_info(psmouse, &info); + if (error) + goto init_fail; + + error = elantech_setup_ps2(psmouse, &info); + if (error) + goto init_fail; + + return 0; + init_fail: + psmouse_reset(psmouse); + return error; +} + +int elantech_init(struct psmouse *psmouse) +{ + struct elantech_device_info info; + int error = -EINVAL; + + psmouse_reset(psmouse); + + error = elantech_query_info(psmouse, &info); + if (error) + goto init_fail; + +#if defined(CONFIG_MOUSE_PS2_ELANTECH_SMBUS) + + if (elantech_use_host_notify(psmouse, &info)) { + if (!IS_ENABLED(CONFIG_MOUSE_ELAN_I2C_SMBUS) || + !IS_ENABLED(CONFIG_MOUSE_PS2_ELANTECH_SMBUS)) { + psmouse_warn(psmouse, + "The touchpad can support a better bus than the too old PS/2 protocol. " + "Make sure MOUSE_PS2_ELANTECH_SMBUS and MOUSE_ELAN_I2C_SMBUS are enabled to get a better touchpad experience.\n"); + } + error = elantech_setup_smbus(psmouse, &info, true); + if (!error) + return PSMOUSE_ELANTECH_SMBUS; + } + +#endif /* CONFIG_MOUSE_PS2_ELANTECH_SMBUS */ + + error = elantech_setup_ps2(psmouse, &info); + if (error < 0) { + /* + * Not using any flavor of Elantech support, so clean up + * SMbus breadcrumbs, if any. + */ + psmouse_smbus_cleanup(psmouse); + goto init_fail; + } + + return PSMOUSE_ELANTECH; + init_fail: + psmouse_reset(psmouse); + return error; +} diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h index e1cbf409d9c8..119727085a60 100644 --- a/drivers/input/mouse/elantech.h +++ b/drivers/input/mouse/elantech.h @@ -107,6 +107,30 @@ #define ETP_WEIGHT_VALUE 5 /* + * Bus information on 3rd byte of query ETP_RESOLUTION_QUERY(0x04) + */ +#define ETP_BUS_PS2_ONLY 0 +#define ETP_BUS_SMB_ALERT_ONLY 1 +#define ETP_BUS_SMB_HST_NTFY_ONLY 2 +#define ETP_BUS_PS2_SMB_ALERT 3 +#define ETP_BUS_PS2_SMB_HST_NTFY 4 + +/* + * New ICs are either using SMBus Host Notify or just plain PS2. + * + * ETP_FW_VERSION_QUERY is: + * Byte 1: + * - bit 0..3: IC BODY + * Byte 2: + * - bit 4: HiddenButton + * - bit 5: PS2_SMBUS_NOTIFY + * - bit 6: PS2CRCCheck + */ +#define ETP_NEW_IC_SMBUS_HOST_NOTIFY(fw_version) \ + ((((fw_version) & 0x0f2000) == 0x0f2000) && \ + ((fw_version) & 0x0000ff) > 0) + +/* * The base position for one finger, v4 hardware */ struct finger_pos { @@ -114,6 +138,25 @@ struct finger_pos { unsigned int y; }; +struct elantech_device_info { + unsigned char capabilities[3]; + unsigned char samples[3]; + unsigned char debug; + unsigned char hw_version; + unsigned int fw_version; + unsigned int x_res; + unsigned int y_res; + unsigned int bus; + bool paritycheck; + bool jumpy_cursor; + bool reports_pressure; + bool crc_enabled; + bool set_hw_resolution; + bool has_trackpoint; + int (*send_cmd)(struct psmouse *psmouse, unsigned char c, + unsigned char *param); +}; + struct elantech_data { struct input_dev *tp_dev; /* Relative device for trackpoint */ char tp_phys[32]; @@ -127,27 +170,18 @@ struct elantech_data { unsigned char reg_24; unsigned char reg_25; unsigned char reg_26; - unsigned char debug; - unsigned char capabilities[3]; - unsigned char samples[3]; - bool paritycheck; - bool jumpy_cursor; - bool reports_pressure; - bool crc_enabled; - bool set_hw_resolution; - unsigned char hw_version; - unsigned int fw_version; unsigned int single_finger_reports; unsigned int y_max; unsigned int width; struct finger_pos mt[ETP_MAX_FINGERS]; unsigned char parity[256]; - int (*send_cmd)(struct psmouse *psmouse, unsigned char c, unsigned char *param); + struct elantech_device_info info; void (*original_set_rate)(struct psmouse *psmouse, unsigned int rate); }; #ifdef CONFIG_MOUSE_PS2_ELANTECH int elantech_detect(struct psmouse *psmouse, bool set_properties); +int elantech_init_ps2(struct psmouse *psmouse); int elantech_init(struct psmouse *psmouse); #else static inline int elantech_detect(struct psmouse *psmouse, bool set_properties) @@ -158,6 +192,19 @@ static inline int elantech_init(struct psmouse *psmouse) { return -ENOSYS; } +static inline int elantech_init_ps2(struct psmouse *psmouse) +{ + return -ENOSYS; +} #endif /* CONFIG_MOUSE_PS2_ELANTECH */ +#if defined(CONFIG_MOUSE_PS2_ELANTECH_SMBUS) +int elantech_init_smbus(struct psmouse *psmouse); +#else +static inline int elantech_init_smbus(struct psmouse *psmouse) +{ + return -ENOSYS; +} +#endif /* CONFIG_MOUSE_PS2_ELANTECH_SMBUS */ + #endif diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 8900c3166ebf..5ff5b1952be0 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -856,7 +856,17 @@ static const struct psmouse_protocol psmouse_protocols[] = { .name = "ETPS/2", .alias = "elantech", .detect = elantech_detect, - .init = elantech_init, + .init = elantech_init_ps2, + }, +#endif +#ifdef CONFIG_MOUSE_PS2_ELANTECH_SMBUS + { + .type = PSMOUSE_ELANTECH_SMBUS, + .name = "ETSMBus", + .alias = "elantech-smbus", + .detect = elantech_detect, + .init = elantech_init_smbus, + .smbus_companion = true, }, #endif #ifdef CONFIG_MOUSE_PS2_SENTELIC @@ -1158,8 +1168,13 @@ static int psmouse_extensions(struct psmouse *psmouse, /* Try Elantech touchpad */ if (max_proto > PSMOUSE_IMEX && psmouse_try_protocol(psmouse, PSMOUSE_ELANTECH, - &max_proto, set_properties, true)) { - return PSMOUSE_ELANTECH; + &max_proto, set_properties, false)) { + if (!set_properties) + return PSMOUSE_ELANTECH; + + ret = elantech_init(psmouse); + if (ret >= 0) + return ret; } if (max_proto > PSMOUSE_IMEX) { diff --git a/drivers/input/mouse/psmouse-smbus.c b/drivers/input/mouse/psmouse-smbus.c index c7ac24d119c1..852d4b486ddb 100644 --- a/drivers/input/mouse/psmouse-smbus.c +++ b/drivers/input/mouse/psmouse-smbus.c @@ -23,6 +23,7 @@ struct psmouse_smbus_dev { struct i2c_client *client; struct list_head node; bool dead; + bool need_deactivate; }; static LIST_HEAD(psmouse_smbus_list); @@ -118,7 +119,10 @@ static psmouse_ret_t psmouse_smbus_process_byte(struct psmouse *psmouse) static int psmouse_smbus_reconnect(struct psmouse *psmouse) { - psmouse_deactivate(psmouse); + struct psmouse_smbus_dev *smbdev = psmouse->private; + + if (smbdev->need_deactivate) + psmouse_deactivate(psmouse); return 0; } @@ -225,6 +229,7 @@ void psmouse_smbus_cleanup(struct psmouse *psmouse) int psmouse_smbus_init(struct psmouse *psmouse, const struct i2c_board_info *board, const void *pdata, size_t pdata_size, + bool need_deactivate, bool leave_breadcrumbs) { struct psmouse_smbus_dev *smbdev; @@ -236,13 +241,20 @@ int psmouse_smbus_init(struct psmouse *psmouse, smbdev->psmouse = psmouse; smbdev->board = *board; + smbdev->need_deactivate = need_deactivate; - smbdev->board.platform_data = kmemdup(pdata, pdata_size, GFP_KERNEL); - if (!smbdev->board.platform_data) { - kfree(smbdev); - return -ENOMEM; + if (pdata) { + smbdev->board.platform_data = kmemdup(pdata, pdata_size, + GFP_KERNEL); + if (!smbdev->board.platform_data) { + kfree(smbdev); + return -ENOMEM; + } } + if (need_deactivate) + psmouse_deactivate(psmouse); + psmouse->private = smbdev; psmouse->protocol_handler = psmouse_smbus_process_byte; psmouse->reconnect = psmouse_smbus_reconnect; @@ -250,8 +262,6 @@ int psmouse_smbus_init(struct psmouse *psmouse, psmouse->disconnect = psmouse_smbus_disconnect; psmouse->resync_time = 0; - psmouse_deactivate(psmouse); - mutex_lock(&psmouse_smbus_mutex); list_add_tail(&smbdev->node, &psmouse_smbus_list); mutex_unlock(&psmouse_smbus_mutex); diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index 71ac50082c8b..64c3a5d3fb3e 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -68,6 +68,7 @@ enum psmouse_type { PSMOUSE_VMMOUSE, PSMOUSE_BYD, PSMOUSE_SYNAPTICS_SMBUS, + PSMOUSE_ELANTECH_SMBUS, PSMOUSE_AUTO /* This one should always be last */ }; @@ -224,6 +225,7 @@ struct i2c_board_info; int psmouse_smbus_init(struct psmouse *psmouse, const struct i2c_board_info *board, const void *pdata, size_t pdata_size, + bool need_deactivate, bool leave_breadcrumbs); void psmouse_smbus_cleanup(struct psmouse *psmouse); diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 60f2c463d1cc..55d33500d55e 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -172,6 +172,12 @@ static const char * const smbus_pnp_ids[] = { "LEN0048", /* X1 Carbon 3 */ "LEN0046", /* X250 */ "LEN004a", /* W541 */ + "LEN0071", /* T480 */ + "LEN0072", /* X1 Carbon Gen 5 (2017) - Elan/ALPS trackpoint */ + "LEN0073", /* X1 Carbon G5 (Elantech) */ + "LEN0092", /* X1 Carbon 6 */ + "LEN0096", /* X280 */ + "LEN0097", /* X280 -> ALPS trackpoint */ "LEN200f", /* T450s */ NULL }; @@ -1748,7 +1754,7 @@ static int synaptics_create_intertouch(struct psmouse *psmouse, }; return psmouse_smbus_init(psmouse, &intertouch_board, - &pdata, sizeof(pdata), + &pdata, sizeof(pdata), true, leave_breadcrumbs); } diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 3e613afa10b4..32267c1afebc 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -164,6 +164,17 @@ config TOUCHSCREEN_CHIPONE_ICN8318 To compile this driver as a module, choose M here: the module will be called chipone_icn8318. +config TOUCHSCREEN_CHIPONE_ICN8505 + tristate "chipone icn8505 touchscreen controller" + depends on I2C && ACPI + help + Say Y here if you have a ChipOne icn8505 based I2C touchscreen. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called chipone_icn8505. + config TOUCHSCREEN_CY8CTMG110 tristate "cy8ctmg110 touchscreen" depends on I2C diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index dddae7973436..fd4fd32fb73f 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT) += atmel_mxt_ts.o obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR) += auo-pixcir-ts.o obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o obj-$(CONFIG_TOUCHSCREEN_CHIPONE_ICN8318) += chipone_icn8318.o +obj-$(CONFIG_TOUCHSCREEN_CHIPONE_ICN8505) += chipone_icn8505.o obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE) += cyttsp_core.o obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C) += cyttsp_i2c.o cyttsp_i2c_common.o diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 09194721aed2..54fe190fd4bc 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -194,6 +194,8 @@ enum t100_type { /* Delay times */ #define MXT_BACKUP_TIME 50 /* msec */ +#define MXT_RESET_GPIO_TIME 20 /* msec */ +#define MXT_RESET_INVALID_CHG 100 /* msec */ #define MXT_RESET_TIME 200 /* msec */ #define MXT_RESET_TIMEOUT 3000 /* msec */ #define MXT_CRC_TIMEOUT 1000 /* msec */ @@ -1208,7 +1210,7 @@ static int mxt_soft_reset(struct mxt_data *data) return ret; /* Ignore CHG line for 100ms after reset */ - msleep(100); + msleep(MXT_RESET_INVALID_CHG); mxt_acquire_irq(data); @@ -2999,142 +3001,6 @@ static int mxt_parse_device_properties(struct mxt_data *data) return 0; } -#ifdef CONFIG_ACPI - -struct mxt_acpi_platform_data { - const char *hid; - const struct property_entry *props; -}; - -static unsigned int samus_touchpad_buttons[] = { - KEY_RESERVED, - KEY_RESERVED, - KEY_RESERVED, - BTN_LEFT -}; - -static const struct property_entry samus_touchpad_props[] = { - PROPERTY_ENTRY_U32_ARRAY("linux,gpio-keymap", samus_touchpad_buttons), - { } -}; - -static struct mxt_acpi_platform_data samus_platform_data[] = { - { - /* Touchpad */ - .hid = "ATML0000", - .props = samus_touchpad_props, - }, - { - /* Touchscreen */ - .hid = "ATML0001", - }, - { } -}; - -static unsigned int chromebook_tp_buttons[] = { - KEY_RESERVED, - KEY_RESERVED, - KEY_RESERVED, - KEY_RESERVED, - KEY_RESERVED, - BTN_LEFT -}; - -static const struct property_entry chromebook_tp_props[] = { - PROPERTY_ENTRY_U32_ARRAY("linux,gpio-keymap", chromebook_tp_buttons), - { } -}; - -static struct mxt_acpi_platform_data chromebook_platform_data[] = { - { - /* Touchpad */ - .hid = "ATML0000", - .props = chromebook_tp_props, - }, - { - /* Touchscreen */ - .hid = "ATML0001", - }, - { } -}; - -static const struct dmi_system_id mxt_dmi_table[] = { - { - /* 2015 Google Pixel */ - .ident = "Chromebook Pixel 2", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"), - DMI_MATCH(DMI_PRODUCT_NAME, "Samus"), - }, - .driver_data = samus_platform_data, - }, - { - /* Samsung Chromebook Pro */ - .ident = "Samsung Chromebook Pro", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Google"), - DMI_MATCH(DMI_PRODUCT_NAME, "Caroline"), - }, - .driver_data = samus_platform_data, - }, - { - /* Other Google Chromebooks */ - .ident = "Chromebook", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"), - }, - .driver_data = chromebook_platform_data, - }, - { } -}; - -static int mxt_prepare_acpi_properties(struct i2c_client *client) -{ - struct acpi_device *adev; - const struct dmi_system_id *system_id; - const struct mxt_acpi_platform_data *acpi_pdata; - - adev = ACPI_COMPANION(&client->dev); - if (!adev) - return -ENOENT; - - system_id = dmi_first_match(mxt_dmi_table); - if (!system_id) - return -ENOENT; - - acpi_pdata = system_id->driver_data; - if (!acpi_pdata) - return -ENOENT; - - while (acpi_pdata->hid) { - if (!strcmp(acpi_device_hid(adev), acpi_pdata->hid)) { - /* - * Remove previously installed properties if we - * are probing this device not for the very first - * time. - */ - device_remove_properties(&client->dev); - - /* - * Now install the platform-specific properties - * that are missing from ACPI. - */ - device_add_properties(&client->dev, acpi_pdata->props); - break; - } - - acpi_pdata++; - } - - return 0; -} -#else -static int mxt_prepare_acpi_properties(struct i2c_client *client) -{ - return -ENOENT; -} -#endif - static const struct dmi_system_id chromebook_T9_suspend_dmi[] = { { .matches = { @@ -3156,6 +3022,18 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id) int error; /* + * Ignore devices that do not have device properties attached to + * them, as we need help determining whether we are dealing with + * touch screen or touchpad. + * + * So far on x86 the only users of Atmel touch controllers are + * Chromebooks, and chromeos_laptop driver will ensure that + * necessary properties are provided (if firmware does not do that). + */ + if (!device_property_present(&client->dev, "compatible")) + return -ENXIO; + + /* * Ignore ACPI devices representing bootloader mode. * * This is a bit of a hack: Google Chromebook BIOS creates ACPI @@ -3186,10 +3064,6 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id) data->suspend_mode = dmi_check_system(chromebook_T9_suspend_dmi) ? MXT_SUSPEND_T9_CTRL : MXT_SUSPEND_DEEP_SLEEP; - error = mxt_prepare_acpi_properties(client); - if (error && error != -ENOENT) - return error; - error = mxt_parse_device_properties(data); if (error) return error; @@ -3210,20 +3084,14 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id) return error; } + disable_irq(client->irq); + if (data->reset_gpio) { - data->in_bootloader = true; - msleep(MXT_RESET_TIME); - reinit_completion(&data->bl_completion); + msleep(MXT_RESET_GPIO_TIME); gpiod_set_value(data->reset_gpio, 1); - error = mxt_wait_for_completion(data, &data->bl_completion, - MXT_RESET_TIMEOUT); - if (error) - return error; - data->in_bootloader = false; + msleep(MXT_RESET_INVALID_CHG); } - disable_irq(client->irq); - error = mxt_initialize(data); if (error) return error; diff --git a/drivers/input/touchscreen/chipone_icn8505.c b/drivers/input/touchscreen/chipone_icn8505.c new file mode 100644 index 000000000000..c768186ce856 --- /dev/null +++ b/drivers/input/touchscreen/chipone_icn8505.c @@ -0,0 +1,520 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Driver for ChipOne icn8505 i2c touchscreen controller + * + * Copyright (c) 2015-2018 Red Hat Inc. + * + * Red Hat authors: + * Hans de Goede <hdegoede@redhat.com> + */ + +#include <asm/unaligned.h> +#include <linux/acpi.h> +#include <linux/crc32.h> +#include <linux/delay.h> +#include <linux/firmware.h> +#include <linux/interrupt.h> +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/input/mt.h> +#include <linux/input/touchscreen.h> +#include <linux/module.h> + +/* Normal operation mode defines */ +#define ICN8505_REG_ADDR_WIDTH 16 + +#define ICN8505_REG_POWER 0x0004 +#define ICN8505_REG_TOUCHDATA 0x1000 +#define ICN8505_REG_CONFIGDATA 0x8000 + +/* ICN8505_REG_POWER commands */ +#define ICN8505_POWER_ACTIVE 0x00 +#define ICN8505_POWER_MONITOR 0x01 +#define ICN8505_POWER_HIBERNATE 0x02 +/* + * The Android driver uses these to turn on/off the charger filter, but the + * filter is way too aggressive making e.g. onscreen keyboards unusable. + */ +#define ICN8505_POWER_ENA_CHARGER_MODE 0x55 +#define ICN8505_POWER_DIS_CHARGER_MODE 0x66 + +#define ICN8505_MAX_TOUCHES 10 + +/* Programming mode defines */ +#define ICN8505_PROG_I2C_ADDR 0x30 +#define ICN8505_PROG_REG_ADDR_WIDTH 24 + +#define MAX_FW_UPLOAD_TRIES 3 + +struct icn8505_touch { + u8 slot; + u8 x[2]; + u8 y[2]; + u8 pressure; /* Seems more like finger width then pressure really */ + u8 event; +/* The difference between 2 and 3 is unclear */ +#define ICN8505_EVENT_NO_DATA 1 /* No finger seen yet since wakeup */ +#define ICN8505_EVENT_UPDATE1 2 /* New or updated coordinates */ +#define ICN8505_EVENT_UPDATE2 3 /* New or updated coordinates */ +#define ICN8505_EVENT_END 4 /* Finger lifted */ +} __packed; + +struct icn8505_touch_data { + u8 softbutton; + u8 touch_count; + struct icn8505_touch touches[ICN8505_MAX_TOUCHES]; +} __packed; + +struct icn8505_data { + struct i2c_client *client; + struct input_dev *input; + struct gpio_desc *wake_gpio; + struct touchscreen_properties prop; + char firmware_name[32]; +}; + +static int icn8505_read_xfer(struct i2c_client *client, u16 i2c_addr, + int reg_addr, int reg_addr_width, + void *data, int len, bool silent) +{ + u8 buf[3]; + int i, ret; + struct i2c_msg msg[2] = { + { + .addr = i2c_addr, + .buf = buf, + .len = reg_addr_width / 8, + }, + { + .addr = i2c_addr, + .flags = I2C_M_RD, + .buf = data, + .len = len, + } + }; + + for (i = 0; i < (reg_addr_width / 8); i++) + buf[i] = (reg_addr >> (reg_addr_width - (i + 1) * 8)) & 0xff; + + ret = i2c_transfer(client->adapter, msg, 2); + if (ret != ARRAY_SIZE(msg)) { + if (ret >= 0) + ret = -EIO; + if (!silent) + dev_err(&client->dev, + "Error reading addr %#x reg %#x: %d\n", + i2c_addr, reg_addr, ret); + return ret; + } + + return 0; +} + +static int icn8505_write_xfer(struct i2c_client *client, u16 i2c_addr, + int reg_addr, int reg_addr_width, + const void *data, int len, bool silent) +{ + u8 buf[3 + 32]; /* 3 bytes for 24 bit reg-addr + 32 bytes max len */ + int i, ret; + struct i2c_msg msg = { + .addr = i2c_addr, + .buf = buf, + .len = reg_addr_width / 8 + len, + }; + + if (WARN_ON(len > 32)) + return -EINVAL; + + for (i = 0; i < (reg_addr_width / 8); i++) + buf[i] = (reg_addr >> (reg_addr_width - (i + 1) * 8)) & 0xff; + + memcpy(buf + reg_addr_width / 8, data, len); + + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret != 1) { + if (ret >= 0) + ret = -EIO; + if (!silent) + dev_err(&client->dev, + "Error writing addr %#x reg %#x: %d\n", + i2c_addr, reg_addr, ret); + return ret; + } + + return 0; +} + +static int icn8505_read_data(struct icn8505_data *icn8505, int reg, + void *buf, int len) +{ + return icn8505_read_xfer(icn8505->client, icn8505->client->addr, reg, + ICN8505_REG_ADDR_WIDTH, buf, len, false); +} + +static int icn8505_read_reg_silent(struct icn8505_data *icn8505, int reg) +{ + u8 buf; + int error; + + error = icn8505_read_xfer(icn8505->client, icn8505->client->addr, reg, + ICN8505_REG_ADDR_WIDTH, &buf, 1, true); + if (error) + return error; + + return buf; +} + +static int icn8505_write_reg(struct icn8505_data *icn8505, int reg, u8 val) +{ + return icn8505_write_xfer(icn8505->client, icn8505->client->addr, reg, + ICN8505_REG_ADDR_WIDTH, &val, 1, false); +} + +static int icn8505_read_prog_data(struct icn8505_data *icn8505, int reg, + void *buf, int len) +{ + return icn8505_read_xfer(icn8505->client, ICN8505_PROG_I2C_ADDR, reg, + ICN8505_PROG_REG_ADDR_WIDTH, buf, len, false); +} + +static int icn8505_write_prog_data(struct icn8505_data *icn8505, int reg, + const void *buf, int len) +{ + return icn8505_write_xfer(icn8505->client, ICN8505_PROG_I2C_ADDR, reg, + ICN8505_PROG_REG_ADDR_WIDTH, buf, len, false); +} + +static int icn8505_write_prog_reg(struct icn8505_data *icn8505, int reg, u8 val) +{ + return icn8505_write_xfer(icn8505->client, ICN8505_PROG_I2C_ADDR, reg, + ICN8505_PROG_REG_ADDR_WIDTH, &val, 1, false); +} + +/* + * Note this function uses a number of magic register addresses and values, + * there are deliberately no defines for these because the algorithm is taken + * from the icn85xx Android driver and I do not want to make up possibly wrong + * names for the addresses and/or values. + */ +static int icn8505_try_fw_upload(struct icn8505_data *icn8505, + const struct firmware *fw) +{ + struct device *dev = &icn8505->client->dev; + size_t offset, count; + int error; + u8 buf[4]; + u32 crc; + + /* Put the controller in programming mode */ + error = icn8505_write_prog_reg(icn8505, 0xcc3355, 0x5a); + if (error) + return error; + + usleep_range(2000, 5000); + + error = icn8505_write_prog_reg(icn8505, 0x040400, 0x01); + if (error) + return error; + + usleep_range(2000, 5000); + + error = icn8505_read_prog_data(icn8505, 0x040002, buf, 1); + if (error) + return error; + + if (buf[0] != 0x85) { + dev_err(dev, "Failed to enter programming mode\n"); + return -ENODEV; + } + + usleep_range(1000, 5000); + + /* Enable CRC mode */ + error = icn8505_write_prog_reg(icn8505, 0x40028, 1); + if (error) + return error; + + /* Send the firmware to SRAM */ + for (offset = 0; offset < fw->size; offset += count) { + count = min_t(size_t, fw->size - offset, 32); + error = icn8505_write_prog_data(icn8505, offset, + fw->data + offset, count); + if (error) + return error; + } + + /* Disable CRC mode */ + error = icn8505_write_prog_reg(icn8505, 0x40028, 0); + if (error) + return error; + + /* Get and check length and CRC */ + error = icn8505_read_prog_data(icn8505, 0x40034, buf, 2); + if (error) + return error; + + if (get_unaligned_le16(buf) != fw->size) { + dev_warn(dev, "Length mismatch after uploading fw\n"); + return -EIO; + } + + error = icn8505_read_prog_data(icn8505, 0x4002c, buf, 4); + if (error) + return error; + + crc = crc32_be(0, fw->data, fw->size); + if (get_unaligned_le32(buf) != crc) { + dev_warn(dev, "CRC mismatch after uploading fw\n"); + return -EIO; + } + + /* Boot controller from SRAM */ + error = icn8505_write_prog_reg(icn8505, 0x40400, 0x03); + if (error) + return error; + + usleep_range(2000, 5000); + return 0; +} + +static int icn8505_upload_fw(struct icn8505_data *icn8505) +{ + struct device *dev = &icn8505->client->dev; + const struct firmware *fw; + int i, error; + + /* + * Always load the firmware, even if we don't need it at boot, we + * we may need it at resume. Having loaded it once will make the + * firmware class code cache it at suspend/resume. + */ + error = request_firmware(&fw, icn8505->firmware_name, dev); + if (error) { + dev_err(dev, "Firmware request error %d\n", error); + return error; + } + + /* Check if the controller is not already up and running */ + if (icn8505_read_reg_silent(icn8505, 0x000a) == 0x85) + goto success; + + for (i = 1; i <= MAX_FW_UPLOAD_TRIES; i++) { + error = icn8505_try_fw_upload(icn8505, fw); + if (!error) + goto success; + + dev_err(dev, "Failed to upload firmware: %d (attempt %d/%d)\n", + error, i, MAX_FW_UPLOAD_TRIES); + usleep_range(2000, 5000); + } + +success: + release_firmware(fw); + return error; +} + +static bool icn8505_touch_active(u8 event) +{ + return event == ICN8505_EVENT_UPDATE1 || + event == ICN8505_EVENT_UPDATE2; +} + +static irqreturn_t icn8505_irq(int irq, void *dev_id) +{ + struct icn8505_data *icn8505 = dev_id; + struct device *dev = &icn8505->client->dev; + struct icn8505_touch_data touch_data; + int i, error; + + error = icn8505_read_data(icn8505, ICN8505_REG_TOUCHDATA, + &touch_data, sizeof(touch_data)); + if (error) { + dev_err(dev, "Error reading touch data: %d\n", error); + return IRQ_HANDLED; + } + + if (touch_data.touch_count > ICN8505_MAX_TOUCHES) { + dev_warn(dev, "Too many touches %d > %d\n", + touch_data.touch_count, ICN8505_MAX_TOUCHES); + touch_data.touch_count = ICN8505_MAX_TOUCHES; + } + + for (i = 0; i < touch_data.touch_count; i++) { + struct icn8505_touch *touch = &touch_data.touches[i]; + bool act = icn8505_touch_active(touch->event); + + input_mt_slot(icn8505->input, touch->slot); + input_mt_report_slot_state(icn8505->input, MT_TOOL_FINGER, act); + if (!act) + continue; + + touchscreen_report_pos(icn8505->input, &icn8505->prop, + get_unaligned_le16(touch->x), + get_unaligned_le16(touch->y), + true); + } + + input_mt_sync_frame(icn8505->input); + input_report_key(icn8505->input, KEY_LEFTMETA, + touch_data.softbutton == 1); + input_sync(icn8505->input); + + return IRQ_HANDLED; +} + +static int icn8505_probe_acpi(struct icn8505_data *icn8505, struct device *dev) +{ + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + const char *subsys = "unknown"; + struct acpi_device *adev; + union acpi_object *obj; + acpi_status status; + + adev = ACPI_COMPANION(dev); + if (!adev) + return -ENODEV; + + status = acpi_evaluate_object(adev->handle, "_SUB", NULL, &buffer); + if (ACPI_SUCCESS(status)) { + obj = buffer.pointer; + if (obj->type == ACPI_TYPE_STRING) + subsys = obj->string.pointer; + else + dev_warn(dev, "Warning ACPI _SUB did not return a string\n"); + } else { + dev_warn(dev, "Warning ACPI _SUB failed: %#x\n", status); + buffer.pointer = NULL; + } + + snprintf(icn8505->firmware_name, sizeof(icn8505->firmware_name), + "chipone/icn8505-%s.fw", subsys); + + kfree(buffer.pointer); + return 0; +} + +static int icn8505_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct icn8505_data *icn8505; + struct input_dev *input; + __le16 resolution[2]; + int error; + + if (!client->irq) { + dev_err(dev, "No irq specified\n"); + return -EINVAL; + } + + icn8505 = devm_kzalloc(dev, sizeof(*icn8505), GFP_KERNEL); + if (!icn8505) + return -ENOMEM; + + input = devm_input_allocate_device(dev); + if (!input) + return -ENOMEM; + + input->name = client->name; + input->id.bustype = BUS_I2C; + + input_set_capability(input, EV_ABS, ABS_MT_POSITION_X); + input_set_capability(input, EV_ABS, ABS_MT_POSITION_Y); + input_set_capability(input, EV_KEY, KEY_LEFTMETA); + + icn8505->client = client; + icn8505->input = input; + input_set_drvdata(input, icn8505); + + error = icn8505_probe_acpi(icn8505, dev); + if (error) + return error; + + error = icn8505_upload_fw(icn8505); + if (error) + return error; + + error = icn8505_read_data(icn8505, ICN8505_REG_CONFIGDATA, + resolution, sizeof(resolution)); + if (error) { + dev_err(dev, "Error reading resolution: %d\n", error); + return error; + } + + input_set_abs_params(input, ABS_MT_POSITION_X, 0, + le16_to_cpu(resolution[0]) - 1, 0, 0); + input_set_abs_params(input, ABS_MT_POSITION_Y, 0, + le16_to_cpu(resolution[1]) - 1, 0, 0); + + touchscreen_parse_properties(input, true, &icn8505->prop); + if (!input_abs_get_max(input, ABS_MT_POSITION_X) || + !input_abs_get_max(input, ABS_MT_POSITION_Y)) { + dev_err(dev, "Error touchscreen-size-x and/or -y missing\n"); + return -EINVAL; + } + + error = input_mt_init_slots(input, ICN8505_MAX_TOUCHES, + INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); + if (error) + return error; + + error = devm_request_threaded_irq(dev, client->irq, NULL, icn8505_irq, + IRQF_ONESHOT, client->name, icn8505); + if (error) { + dev_err(dev, "Error requesting irq: %d\n", error); + return error; + } + + error = input_register_device(input); + if (error) + return error; + + i2c_set_clientdata(client, icn8505); + return 0; +} + +static int __maybe_unused icn8505_suspend(struct device *dev) +{ + struct icn8505_data *icn8505 = i2c_get_clientdata(to_i2c_client(dev)); + + disable_irq(icn8505->client->irq); + + icn8505_write_reg(icn8505, ICN8505_REG_POWER, ICN8505_POWER_HIBERNATE); + + return 0; +} + +static int __maybe_unused icn8505_resume(struct device *dev) +{ + struct icn8505_data *icn8505 = i2c_get_clientdata(to_i2c_client(dev)); + int error; + + error = icn8505_upload_fw(icn8505); + if (error) + return error; + + enable_irq(icn8505->client->irq); + return 0; +} + +static SIMPLE_DEV_PM_OPS(icn8505_pm_ops, icn8505_suspend, icn8505_resume); + +static const struct acpi_device_id icn8505_acpi_match[] = { + { "CHPN0001" }, + { } +}; +MODULE_DEVICE_TABLE(acpi, icn8505_acpi_match); + +static struct i2c_driver icn8505_driver = { + .driver = { + .name = "chipone_icn8505", + .pm = &icn8505_pm_ops, + .acpi_match_table = icn8505_acpi_match, + }, + .probe_new = icn8505_probe, +}; + +module_i2c_driver(icn8505_driver); + +MODULE_DESCRIPTION("ChipOne icn8505 I2C Touchscreen Driver"); +MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c index 9736c83dd418..f2d9c2c41885 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -933,6 +933,7 @@ MODULE_DEVICE_TABLE(i2c, goodix_ts_id); #ifdef CONFIG_ACPI static const struct acpi_device_id goodix_acpi_match[] = { { "GDIX1001", 0 }, + { "GDIX1002", 0 }, { } }; MODULE_DEVICE_TABLE(acpi, goodix_acpi_match); diff --git a/drivers/input/touchscreen/mk712.c b/drivers/input/touchscreen/mk712.c index bd5352824f77..c179060525ae 100644 --- a/drivers/input/touchscreen/mk712.c +++ b/drivers/input/touchscreen/mk712.c @@ -17,7 +17,7 @@ * found in Gateway AOL Connected Touchpad computers. * * Documentation for ICS MK712 can be found at: - * http://www.idt.com/products/getDoc.cfm?docID=18713923 + * https://www.idt.com/general-parts/mk712-touch-screen-controller */ /* diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c index f1043ae71dcc..b86c1e5fbc11 100644 --- a/drivers/input/touchscreen/ti_am335x_tsc.c +++ b/drivers/input/touchscreen/ti_am335x_tsc.c @@ -34,6 +34,8 @@ #define SEQ_SETTLE 275 #define MAX_12BIT ((1 << 12) - 1) +#define TSC_IRQENB_MASK (IRQENB_FIFO0THRES | IRQENB_EOS | IRQENB_HW_PEN) + static const int config_pins[] = { STEPCONFIG_XPP, STEPCONFIG_XNN, @@ -274,6 +276,7 @@ static irqreturn_t titsc_irq(int irq, void *dev) if (status & IRQENB_HW_PEN) { ts_dev->pen_down = true; irqclr |= IRQENB_HW_PEN; + pm_stay_awake(ts_dev->mfd_tscadc->dev); } if (status & IRQENB_PENUP) { @@ -283,6 +286,7 @@ static irqreturn_t titsc_irq(int irq, void *dev) input_report_key(input_dev, BTN_TOUCH, 0); input_report_abs(input_dev, ABS_PRESSURE, 0); input_sync(input_dev); + pm_relax(ts_dev->mfd_tscadc->dev); } else { ts_dev->pen_down = true; } @@ -432,6 +436,7 @@ static int titsc_probe(struct platform_device *pdev) goto err_free_mem; } + titsc_writel(ts_dev, REG_IRQSTATUS, TSC_IRQENB_MASK); titsc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO0THRES); titsc_writel(ts_dev, REG_IRQENABLE, IRQENB_EOS); err = titsc_config_wires(ts_dev); @@ -495,6 +500,7 @@ static int __maybe_unused titsc_suspend(struct device *dev) tscadc_dev = ti_tscadc_dev_get(to_platform_device(dev)); if (device_may_wakeup(tscadc_dev->dev)) { + titsc_writel(ts_dev, REG_IRQSTATUS, TSC_IRQENB_MASK); idle = titsc_readl(ts_dev, REG_IRQENABLE); titsc_writel(ts_dev, REG_IRQENABLE, (idle | IRQENB_HW_PEN)); @@ -513,6 +519,7 @@ static int __maybe_unused titsc_resume(struct device *dev) titsc_writel(ts_dev, REG_IRQWAKEUP, 0x00); titsc_writel(ts_dev, REG_IRQCLR, IRQENB_HW_PEN); + pm_relax(ts_dev->mfd_tscadc->dev); } titsc_step_config(ts_dev); titsc_writel(ts_dev, REG_FIFO0THR, diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c index c6cf90868503..d61570d64ee7 100644 --- a/drivers/input/touchscreen/usbtouchscreen.c +++ b/drivers/input/touchscreen/usbtouchscreen.c @@ -440,6 +440,8 @@ static int panjit_read_data(struct usbtouch_usb *dev, unsigned char *pkt) #define MTOUCHUSB_RESET 7 #define MTOUCHUSB_REQ_CTRLLR_ID 10 +#define MTOUCHUSB_REQ_CTRLLR_ID_LEN 16 + static int mtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt) { if (hwcalib_xy) { @@ -454,11 +456,93 @@ static int mtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt) return 1; } +struct mtouch_priv { + u8 fw_rev_major; + u8 fw_rev_minor; +}; + +static ssize_t mtouch_firmware_rev_show(struct device *dev, + struct device_attribute *attr, char *output) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct usbtouch_usb *usbtouch = usb_get_intfdata(intf); + struct mtouch_priv *priv = usbtouch->priv; + + return scnprintf(output, PAGE_SIZE, "%1x.%1x\n", + priv->fw_rev_major, priv->fw_rev_minor); +} +static DEVICE_ATTR(firmware_rev, 0444, mtouch_firmware_rev_show, NULL); + +static struct attribute *mtouch_attrs[] = { + &dev_attr_firmware_rev.attr, + NULL +}; + +static const struct attribute_group mtouch_attr_group = { + .attrs = mtouch_attrs, +}; + +static int mtouch_get_fw_revision(struct usbtouch_usb *usbtouch) +{ + struct usb_device *udev = interface_to_usbdev(usbtouch->interface); + struct mtouch_priv *priv = usbtouch->priv; + u8 *buf; + int ret; + + buf = kzalloc(MTOUCHUSB_REQ_CTRLLR_ID_LEN, GFP_NOIO); + if (!buf) + return -ENOMEM; + + ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + MTOUCHUSB_REQ_CTRLLR_ID, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, 0, buf, MTOUCHUSB_REQ_CTRLLR_ID_LEN, + USB_CTRL_SET_TIMEOUT); + if (ret != MTOUCHUSB_REQ_CTRLLR_ID_LEN) { + dev_warn(&usbtouch->interface->dev, + "Failed to read FW rev: %d\n", ret); + ret = ret < 0 ? ret : -EIO; + goto free; + } + + priv->fw_rev_major = buf[3]; + priv->fw_rev_minor = buf[4]; + + ret = 0; + +free: + kfree(buf); + return ret; +} + +static int mtouch_alloc(struct usbtouch_usb *usbtouch) +{ + int ret; + + usbtouch->priv = kmalloc(sizeof(struct mtouch_priv), GFP_KERNEL); + if (!usbtouch->priv) + return -ENOMEM; + + ret = sysfs_create_group(&usbtouch->interface->dev.kobj, + &mtouch_attr_group); + if (ret) { + kfree(usbtouch->priv); + usbtouch->priv = NULL; + return ret; + } + + return 0; +} + static int mtouch_init(struct usbtouch_usb *usbtouch) { int ret, i; struct usb_device *udev = interface_to_usbdev(usbtouch->interface); + ret = mtouch_get_fw_revision(usbtouch); + if (ret) + return ret; + ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), MTOUCHUSB_RESET, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, @@ -492,6 +576,14 @@ static int mtouch_init(struct usbtouch_usb *usbtouch) return 0; } + +static void mtouch_exit(struct usbtouch_usb *usbtouch) +{ + struct mtouch_priv *priv = usbtouch->priv; + + sysfs_remove_group(&usbtouch->interface->dev.kobj, &mtouch_attr_group); + kfree(priv); +} #endif @@ -1119,7 +1211,9 @@ static struct usbtouch_device_info usbtouch_dev_info[] = { .max_yc = 0x4000, .rept_size = 11, .read_data = mtouch_read_data, + .alloc = mtouch_alloc, .init = mtouch_init, + .exit = mtouch_exit, }, #endif diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index df171cb85822..5b714a062fa7 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -146,6 +146,7 @@ config INTEL_IOMMU select DMA_DIRECT_OPS select IOMMU_API select IOMMU_IOVA + select NEED_DMA_MAP_STATE select DMAR_TABLE help DMA remapping (DMAR) devices support enables independent address diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 5ed465ab1c76..15f268f646bf 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -27,7 +27,7 @@ obj-$(CONFIG_ARM_GIC) += irq-gic.o irq-gic-common.o obj-$(CONFIG_ARM_GIC_PM) += irq-gic-pm.o obj-$(CONFIG_ARCH_REALVIEW) += irq-gic-realview.o obj-$(CONFIG_ARM_GIC_V2M) += irq-gic-v2m.o -obj-$(CONFIG_ARM_GIC_V3) += irq-gic-v3.o irq-gic-common.o +obj-$(CONFIG_ARM_GIC_V3) += irq-gic-v3.o irq-gic-v3-mbi.o irq-gic-common.o obj-$(CONFIG_ARM_GIC_V3_ITS) += irq-gic-v3-its.o irq-gic-v3-its-platform-msi.o irq-gic-v4.o obj-$(CONFIG_ARM_GIC_V3_ITS_PCI) += irq-gic-v3-its-pci-msi.o obj-$(CONFIG_ARM_GIC_V3_ITS_FSL_MC) += irq-gic-v3-its-fsl-mc-msi.o diff --git a/drivers/irqchip/irq-gic-v3-mbi.c b/drivers/irqchip/irq-gic-v3-mbi.c new file mode 100644 index 000000000000..ad70e7c416e3 --- /dev/null +++ b/drivers/irqchip/irq-gic-v3-mbi.c @@ -0,0 +1,331 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 ARM Limited, All Rights Reserved. + * Author: Marc Zyngier <marc.zyngier@arm.com> + */ + +#define pr_fmt(fmt) "GICv3: " fmt + +#include <linux/dma-iommu.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/kernel.h> +#include <linux/msi.h> +#include <linux/of_address.h> +#include <linux/of_pci.h> +#include <linux/slab.h> +#include <linux/spinlock.h> + +#include <linux/irqchip/arm-gic-v3.h> + +struct mbi_range { + u32 spi_start; + u32 nr_spis; + unsigned long *bm; +}; + +static struct mutex mbi_lock; +static phys_addr_t mbi_phys_base; +static struct mbi_range *mbi_ranges; +static unsigned int mbi_range_nr; + +static struct irq_chip mbi_irq_chip = { + .name = "MBI", + .irq_mask = irq_chip_mask_parent, + .irq_unmask = irq_chip_unmask_parent, + .irq_eoi = irq_chip_eoi_parent, + .irq_set_type = irq_chip_set_type_parent, + .irq_set_affinity = irq_chip_set_affinity_parent, +}; + +static int mbi_irq_gic_domain_alloc(struct irq_domain *domain, + unsigned int virq, + irq_hw_number_t hwirq) +{ + struct irq_fwspec fwspec; + struct irq_data *d; + int err; + + /* + * Using ACPI? There is no MBI support in the spec, you + * shouldn't even be here. + */ + if (!is_of_node(domain->parent->fwnode)) + return -EINVAL; + + /* + * Let's default to edge. This is consistent with traditional + * MSIs, and systems requiring level signaling will just + * enforce the trigger on their own. + */ + fwspec.fwnode = domain->parent->fwnode; + fwspec.param_count = 3; + fwspec.param[0] = 0; + fwspec.param[1] = hwirq - 32; + fwspec.param[2] = IRQ_TYPE_EDGE_RISING; + + err = irq_domain_alloc_irqs_parent(domain, virq, 1, &fwspec); + if (err) + return err; + + d = irq_domain_get_irq_data(domain->parent, virq); + return d->chip->irq_set_type(d, IRQ_TYPE_EDGE_RISING); +} + +static void mbi_free_msi(struct mbi_range *mbi, unsigned int hwirq, + int nr_irqs) +{ + mutex_lock(&mbi_lock); + bitmap_release_region(mbi->bm, hwirq - mbi->spi_start, + get_count_order(nr_irqs)); + mutex_unlock(&mbi_lock); +} + +static int mbi_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, + unsigned int nr_irqs, void *args) +{ + struct mbi_range *mbi = NULL; + int hwirq, offset, i, err = 0; + + mutex_lock(&mbi_lock); + for (i = 0; i < mbi_range_nr; i++) { + offset = bitmap_find_free_region(mbi_ranges[i].bm, + mbi_ranges[i].nr_spis, + get_count_order(nr_irqs)); + if (offset >= 0) { + mbi = &mbi_ranges[i]; + break; + } + } + mutex_unlock(&mbi_lock); + + if (!mbi) + return -ENOSPC; + + hwirq = mbi->spi_start + offset; + + for (i = 0; i < nr_irqs; i++) { + err = mbi_irq_gic_domain_alloc(domain, virq + i, hwirq + i); + if (err) + goto fail; + + irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i, + &mbi_irq_chip, mbi); + } + + return 0; + +fail: + irq_domain_free_irqs_parent(domain, virq, nr_irqs); + mbi_free_msi(mbi, hwirq, nr_irqs); + return err; +} + +static void mbi_irq_domain_free(struct irq_domain *domain, + unsigned int virq, unsigned int nr_irqs) +{ + struct irq_data *d = irq_domain_get_irq_data(domain, virq); + struct mbi_range *mbi = irq_data_get_irq_chip_data(d); + + mbi_free_msi(mbi, d->hwirq, nr_irqs); + irq_domain_free_irqs_parent(domain, virq, nr_irqs); +} + +static const struct irq_domain_ops mbi_domain_ops = { + .alloc = mbi_irq_domain_alloc, + .free = mbi_irq_domain_free, +}; + +static void mbi_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) +{ + msg[0].address_hi = upper_32_bits(mbi_phys_base + GICD_SETSPI_NSR); + msg[0].address_lo = lower_32_bits(mbi_phys_base + GICD_SETSPI_NSR); + msg[0].data = data->parent_data->hwirq; + + iommu_dma_map_msi_msg(data->irq, msg); +} + +#ifdef CONFIG_PCI_MSI +/* PCI-specific irqchip */ +static void mbi_mask_msi_irq(struct irq_data *d) +{ + pci_msi_mask_irq(d); + irq_chip_mask_parent(d); +} + +static void mbi_unmask_msi_irq(struct irq_data *d) +{ + pci_msi_unmask_irq(d); + irq_chip_unmask_parent(d); +} + +static struct irq_chip mbi_msi_irq_chip = { + .name = "MSI", + .irq_mask = mbi_mask_msi_irq, + .irq_unmask = mbi_unmask_msi_irq, + .irq_eoi = irq_chip_eoi_parent, + .irq_compose_msi_msg = mbi_compose_msi_msg, + .irq_write_msi_msg = pci_msi_domain_write_msg, +}; + +static struct msi_domain_info mbi_msi_domain_info = { + .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | + MSI_FLAG_PCI_MSIX | MSI_FLAG_MULTI_PCI_MSI), + .chip = &mbi_msi_irq_chip, +}; + +static int mbi_allocate_pci_domain(struct irq_domain *nexus_domain, + struct irq_domain **pci_domain) +{ + *pci_domain = pci_msi_create_irq_domain(nexus_domain->parent->fwnode, + &mbi_msi_domain_info, + nexus_domain); + if (!*pci_domain) + return -ENOMEM; + + return 0; +} +#else +static int mbi_allocate_pci_domain(struct irq_domain *nexus_domain, + struct irq_domain **pci_domain) +{ + *pci_domain = NULL; + return 0; +} +#endif + +static void mbi_compose_mbi_msg(struct irq_data *data, struct msi_msg *msg) +{ + mbi_compose_msi_msg(data, msg); + + msg[1].address_hi = upper_32_bits(mbi_phys_base + GICD_CLRSPI_NSR); + msg[1].address_lo = lower_32_bits(mbi_phys_base + GICD_CLRSPI_NSR); + msg[1].data = data->parent_data->hwirq; + + iommu_dma_map_msi_msg(data->irq, &msg[1]); +} + +/* Platform-MSI specific irqchip */ +static struct irq_chip mbi_pmsi_irq_chip = { + .name = "pMSI", + .irq_set_type = irq_chip_set_type_parent, + .irq_compose_msi_msg = mbi_compose_mbi_msg, + .flags = IRQCHIP_SUPPORTS_LEVEL_MSI, +}; + +static struct msi_domain_ops mbi_pmsi_ops = { +}; + +static struct msi_domain_info mbi_pmsi_domain_info = { + .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | + MSI_FLAG_LEVEL_CAPABLE), + .ops = &mbi_pmsi_ops, + .chip = &mbi_pmsi_irq_chip, +}; + +static int mbi_allocate_domains(struct irq_domain *parent) +{ + struct irq_domain *nexus_domain, *pci_domain, *plat_domain; + int err; + + nexus_domain = irq_domain_create_tree(parent->fwnode, + &mbi_domain_ops, NULL); + if (!nexus_domain) + return -ENOMEM; + + irq_domain_update_bus_token(nexus_domain, DOMAIN_BUS_NEXUS); + nexus_domain->parent = parent; + + err = mbi_allocate_pci_domain(nexus_domain, &pci_domain); + + plat_domain = platform_msi_create_irq_domain(parent->fwnode, + &mbi_pmsi_domain_info, + nexus_domain); + + if (err || !plat_domain) { + if (plat_domain) + irq_domain_remove(plat_domain); + if (pci_domain) + irq_domain_remove(pci_domain); + irq_domain_remove(nexus_domain); + return -ENOMEM; + } + + return 0; +} + +int __init mbi_init(struct fwnode_handle *fwnode, struct irq_domain *parent) +{ + struct device_node *np; + const __be32 *reg; + int ret, n; + + np = to_of_node(fwnode); + + if (!of_property_read_bool(np, "msi-controller")) + return 0; + + n = of_property_count_elems_of_size(np, "mbi-ranges", sizeof(u32)); + if (n <= 0 || n % 2) + return -EINVAL; + + mbi_range_nr = n / 2; + mbi_ranges = kcalloc(mbi_range_nr, sizeof(*mbi_ranges), GFP_KERNEL); + if (!mbi_ranges) + return -ENOMEM; + + for (n = 0; n < mbi_range_nr; n++) { + ret = of_property_read_u32_index(np, "mbi-ranges", n * 2, + &mbi_ranges[n].spi_start); + if (ret) + goto err_free_mbi; + ret = of_property_read_u32_index(np, "mbi-ranges", n * 2 + 1, + &mbi_ranges[n].nr_spis); + if (ret) + goto err_free_mbi; + + mbi_ranges[n].bm = kcalloc(BITS_TO_LONGS(mbi_ranges[n].nr_spis), + sizeof(long), GFP_KERNEL); + if (!mbi_ranges[n].bm) { + ret = -ENOMEM; + goto err_free_mbi; + } + pr_info("MBI range [%d:%d]\n", mbi_ranges[n].spi_start, + mbi_ranges[n].spi_start + mbi_ranges[n].nr_spis - 1); + } + + reg = of_get_property(np, "mbi-alias", NULL); + if (reg) { + mbi_phys_base = of_translate_address(np, reg); + if (mbi_phys_base == OF_BAD_ADDR) { + ret = -ENXIO; + goto err_free_mbi; + } + } else { + struct resource res; + + if (of_address_to_resource(np, 0, &res)) { + ret = -ENXIO; + goto err_free_mbi; + } + + mbi_phys_base = res.start; + } + + pr_info("Using MBI frame %pa\n", &mbi_phys_base); + + ret = mbi_allocate_domains(parent); + if (ret) + goto err_free_mbi; + + return 0; + +err_free_mbi: + if (mbi_ranges) { + for (n = 0; n < mbi_range_nr; n++) + kfree(mbi_ranges[n].bm); + kfree(mbi_ranges); + } + + return ret; +} diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index e5d101418390..5a67ec084588 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -1099,6 +1099,7 @@ static int __init gic_init_bases(void __iomem *dist_base, gic_data.domain = irq_domain_create_tree(handle, &gic_irq_domain_ops, &gic_data); + irq_domain_update_bus_token(gic_data.domain, DOMAIN_BUS_WIRED); gic_data.rdists.rdist = alloc_percpu(typeof(*gic_data.rdists.rdist)); gic_data.rdists.has_vlpis = true; gic_data.rdists.has_direct_lpi = true; @@ -1112,6 +1113,12 @@ static int __init gic_init_bases(void __iomem *dist_base, pr_info("Distributor has %sRange Selector support\n", gic_data.has_rss ? "" : "no "); + if (typer & GICD_TYPER_MBIS) { + err = mbi_init(handle, gic_data.domain); + if (err) + pr_err("Failed to initialize MBIs\n"); + } + set_handle_irq(gic_handle_irq); gic_update_vlpi_properties(); diff --git a/drivers/irqchip/irq-meson-gpio.c b/drivers/irqchip/irq-meson-gpio.c index a59bdbc0b9bb..7b531fd075b8 100644 --- a/drivers/irqchip/irq-meson-gpio.c +++ b/drivers/irqchip/irq-meson-gpio.c @@ -63,11 +63,16 @@ static const struct meson_gpio_irq_params gxl_params = { .nr_hwirq = 110, }; +static const struct meson_gpio_irq_params axg_params = { + .nr_hwirq = 100, +}; + static const struct of_device_id meson_irq_gpio_matches[] = { { .compatible = "amlogic,meson8-gpio-intc", .data = &meson8_params }, { .compatible = "amlogic,meson8b-gpio-intc", .data = &meson8b_params }, { .compatible = "amlogic,meson-gxbb-gpio-intc", .data = &gxbb_params }, { .compatible = "amlogic,meson-gxl-gpio-intc", .data = &gxl_params }, + { .compatible = "amlogic,meson-axg-gpio-intc", .data = &axg_params }, { } }; diff --git a/drivers/irqchip/irq-mvebu-gicp.c b/drivers/irqchip/irq-mvebu-gicp.c index 17a4a7b6cdbb..4e17f7081efc 100644 --- a/drivers/irqchip/irq-mvebu-gicp.c +++ b/drivers/irqchip/irq-mvebu-gicp.c @@ -19,8 +19,6 @@ #include <dt-bindings/interrupt-controller/arm-gic.h> -#include "irq-mvebu-gicp.h" - #define GICP_SETSPI_NSR_OFFSET 0x0 #define GICP_CLRSPI_NSR_OFFSET 0x8 @@ -55,34 +53,18 @@ static int gicp_idx_to_spi(struct mvebu_gicp *gicp, int idx) return -EINVAL; } -int mvebu_gicp_get_doorbells(struct device_node *dn, phys_addr_t *setspi, - phys_addr_t *clrspi) -{ - struct platform_device *pdev; - struct mvebu_gicp *gicp; - - pdev = of_find_device_by_node(dn); - if (!pdev) - return -ENODEV; - - gicp = platform_get_drvdata(pdev); - if (!gicp) - return -ENODEV; - - *setspi = gicp->res->start + GICP_SETSPI_NSR_OFFSET; - *clrspi = gicp->res->start + GICP_CLRSPI_NSR_OFFSET; - - return 0; -} - static void gicp_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) { struct mvebu_gicp *gicp = data->chip_data; phys_addr_t setspi = gicp->res->start + GICP_SETSPI_NSR_OFFSET; - - msg->data = data->hwirq; - msg->address_lo = lower_32_bits(setspi); - msg->address_hi = upper_32_bits(setspi); + phys_addr_t clrspi = gicp->res->start + GICP_CLRSPI_NSR_OFFSET; + + msg[0].data = data->hwirq; + msg[0].address_lo = lower_32_bits(setspi); + msg[0].address_hi = upper_32_bits(setspi); + msg[1].data = data->hwirq; + msg[1].address_lo = lower_32_bits(clrspi); + msg[1].address_hi = upper_32_bits(clrspi); } static struct irq_chip gicp_irq_chip = { @@ -170,13 +152,15 @@ static const struct irq_domain_ops gicp_domain_ops = { static struct irq_chip gicp_msi_irq_chip = { .name = "GICP", .irq_set_type = irq_chip_set_type_parent, + .flags = IRQCHIP_SUPPORTS_LEVEL_MSI, }; static struct msi_domain_ops gicp_msi_ops = { }; static struct msi_domain_info gicp_msi_domain_info = { - .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS), + .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | + MSI_FLAG_LEVEL_CAPABLE), .ops = &gicp_msi_ops, .chip = &gicp_msi_irq_chip, }; diff --git a/drivers/irqchip/irq-mvebu-gicp.h b/drivers/irqchip/irq-mvebu-gicp.h deleted file mode 100644 index eaa12fb72102..000000000000 --- a/drivers/irqchip/irq-mvebu-gicp.h +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __MVEBU_GICP_H__ -#define __MVEBU_GICP_H__ - -#include <linux/types.h> - -struct device_node; - -int mvebu_gicp_get_doorbells(struct device_node *dn, phys_addr_t *setspi, - phys_addr_t *clrspi); - -#endif /* __MVEBU_GICP_H__ */ diff --git a/drivers/irqchip/irq-mvebu-icu.c b/drivers/irqchip/irq-mvebu-icu.c index e18c48d3a92e..13063339b416 100644 --- a/drivers/irqchip/irq-mvebu-icu.c +++ b/drivers/irqchip/irq-mvebu-icu.c @@ -21,8 +21,6 @@ #include <dt-bindings/interrupt-controller/mvebu-icu.h> -#include "irq-mvebu-gicp.h" - /* ICU registers */ #define ICU_SETSPI_NSR_AL 0x10 #define ICU_SETSPI_NSR_AH 0x14 @@ -43,6 +41,7 @@ struct mvebu_icu { void __iomem *base; struct irq_domain *domain; struct device *dev; + atomic_t initialized; }; struct mvebu_icu_irq_data { @@ -51,6 +50,18 @@ struct mvebu_icu_irq_data { unsigned int type; }; +static void mvebu_icu_init(struct mvebu_icu *icu, struct msi_msg *msg) +{ + if (atomic_cmpxchg(&icu->initialized, false, true)) + return; + + /* Set Clear/Set ICU SPI message address in AP */ + writel_relaxed(msg[0].address_hi, icu->base + ICU_SETSPI_NSR_AH); + writel_relaxed(msg[0].address_lo, icu->base + ICU_SETSPI_NSR_AL); + writel_relaxed(msg[1].address_hi, icu->base + ICU_CLRSPI_NSR_AH); + writel_relaxed(msg[1].address_lo, icu->base + ICU_CLRSPI_NSR_AL); +} + static void mvebu_icu_write_msg(struct msi_desc *desc, struct msi_msg *msg) { struct irq_data *d = irq_get_irq_data(desc->irq); @@ -59,6 +70,8 @@ static void mvebu_icu_write_msg(struct msi_desc *desc, struct msi_msg *msg) unsigned int icu_int; if (msg->address_lo || msg->address_hi) { + /* One off initialization */ + mvebu_icu_init(icu, msg); /* Configure the ICU with irq number & type */ icu_int = msg->data | ICU_INT_ENABLE; if (icu_irqd->type & IRQ_TYPE_EDGE_RISING) @@ -197,9 +210,7 @@ static int mvebu_icu_probe(struct platform_device *pdev) struct device_node *node = pdev->dev.of_node; struct device_node *gicp_dn; struct resource *res; - phys_addr_t setspi, clrspi; - u32 i, icu_int; - int ret; + int i; icu = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_icu), GFP_KERNEL); @@ -242,22 +253,12 @@ static int mvebu_icu_probe(struct platform_device *pdev) if (!gicp_dn) return -ENODEV; - ret = mvebu_gicp_get_doorbells(gicp_dn, &setspi, &clrspi); - if (ret) - return ret; - - /* Set Clear/Set ICU SPI message address in AP */ - writel_relaxed(upper_32_bits(setspi), icu->base + ICU_SETSPI_NSR_AH); - writel_relaxed(lower_32_bits(setspi), icu->base + ICU_SETSPI_NSR_AL); - writel_relaxed(upper_32_bits(clrspi), icu->base + ICU_CLRSPI_NSR_AH); - writel_relaxed(lower_32_bits(clrspi), icu->base + ICU_CLRSPI_NSR_AL); - /* * Clean all ICU interrupts with type SPI_NSR, required to * avoid unpredictable SPI assignments done by firmware. */ for (i = 0 ; i < ICU_MAX_IRQS ; i++) { - icu_int = readl(icu->base + ICU_INT_CFG(i)); + u32 icu_int = readl_relaxed(icu->base + ICU_INT_CFG(i)); if ((icu_int >> ICU_GROUP_SHIFT) == ICU_GRP_NSR) writel_relaxed(0x0, icu->base + ICU_INT_CFG(i)); } diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c index 36f0fbe36c35..5089c1e2838d 100644 --- a/drivers/irqchip/irq-stm32-exti.c +++ b/drivers/irqchip/irq-stm32-exti.c @@ -14,6 +14,9 @@ #include <linux/irqdomain.h> #include <linux/of_address.h> #include <linux/of_irq.h> +#include <linux/syscore_ops.h> + +#include <dt-bindings/interrupt-controller/arm-gic.h> #define IRQS_PER_BANK 32 @@ -23,29 +26,69 @@ struct stm32_exti_bank { u32 rtsr_ofst; u32 ftsr_ofst; u32 swier_ofst; - u32 pr_ofst; + u32 rpr_ofst; + u32 fpr_ofst; +}; + +#define UNDEF_REG ~0 + +struct stm32_desc_irq { + u32 exti; + u32 irq_parent; +}; + +struct stm32_exti_drv_data { + const struct stm32_exti_bank **exti_banks; + const struct stm32_desc_irq *desc_irqs; + u32 bank_nr; + u32 irq_nr; +}; + +struct stm32_exti_chip_data { + struct stm32_exti_host_data *host_data; + const struct stm32_exti_bank *reg_bank; + struct raw_spinlock rlock; + u32 wake_active; + u32 mask_cache; + u32 rtsr_cache; + u32 ftsr_cache; }; +struct stm32_exti_host_data { + void __iomem *base; + struct stm32_exti_chip_data *chips_data; + const struct stm32_exti_drv_data *drv_data; +}; + +static struct stm32_exti_host_data *stm32_host_data; + static const struct stm32_exti_bank stm32f4xx_exti_b1 = { .imr_ofst = 0x00, .emr_ofst = 0x04, .rtsr_ofst = 0x08, .ftsr_ofst = 0x0C, .swier_ofst = 0x10, - .pr_ofst = 0x14, + .rpr_ofst = 0x14, + .fpr_ofst = UNDEF_REG, }; static const struct stm32_exti_bank *stm32f4xx_exti_banks[] = { &stm32f4xx_exti_b1, }; +static const struct stm32_exti_drv_data stm32f4xx_drv_data = { + .exti_banks = stm32f4xx_exti_banks, + .bank_nr = ARRAY_SIZE(stm32f4xx_exti_banks), +}; + static const struct stm32_exti_bank stm32h7xx_exti_b1 = { .imr_ofst = 0x80, .emr_ofst = 0x84, .rtsr_ofst = 0x00, .ftsr_ofst = 0x04, .swier_ofst = 0x08, - .pr_ofst = 0x88, + .rpr_ofst = 0x88, + .fpr_ofst = UNDEF_REG, }; static const struct stm32_exti_bank stm32h7xx_exti_b2 = { @@ -54,7 +97,8 @@ static const struct stm32_exti_bank stm32h7xx_exti_b2 = { .rtsr_ofst = 0x20, .ftsr_ofst = 0x24, .swier_ofst = 0x28, - .pr_ofst = 0x98, + .rpr_ofst = 0x98, + .fpr_ofst = UNDEF_REG, }; static const struct stm32_exti_bank stm32h7xx_exti_b3 = { @@ -63,7 +107,8 @@ static const struct stm32_exti_bank stm32h7xx_exti_b3 = { .rtsr_ofst = 0x40, .ftsr_ofst = 0x44, .swier_ofst = 0x48, - .pr_ofst = 0xA8, + .rpr_ofst = 0xA8, + .fpr_ofst = UNDEF_REG, }; static const struct stm32_exti_bank *stm32h7xx_exti_banks[] = { @@ -72,18 +117,105 @@ static const struct stm32_exti_bank *stm32h7xx_exti_banks[] = { &stm32h7xx_exti_b3, }; -static unsigned long stm32_exti_pending(struct irq_chip_generic *gc) +static const struct stm32_exti_drv_data stm32h7xx_drv_data = { + .exti_banks = stm32h7xx_exti_banks, + .bank_nr = ARRAY_SIZE(stm32h7xx_exti_banks), +}; + +static const struct stm32_exti_bank stm32mp1_exti_b1 = { + .imr_ofst = 0x80, + .emr_ofst = 0x84, + .rtsr_ofst = 0x00, + .ftsr_ofst = 0x04, + .swier_ofst = 0x08, + .rpr_ofst = 0x0C, + .fpr_ofst = 0x10, +}; + +static const struct stm32_exti_bank stm32mp1_exti_b2 = { + .imr_ofst = 0x90, + .emr_ofst = 0x94, + .rtsr_ofst = 0x20, + .ftsr_ofst = 0x24, + .swier_ofst = 0x28, + .rpr_ofst = 0x2C, + .fpr_ofst = 0x30, +}; + +static const struct stm32_exti_bank stm32mp1_exti_b3 = { + .imr_ofst = 0xA0, + .emr_ofst = 0xA4, + .rtsr_ofst = 0x40, + .ftsr_ofst = 0x44, + .swier_ofst = 0x48, + .rpr_ofst = 0x4C, + .fpr_ofst = 0x50, +}; + +static const struct stm32_exti_bank *stm32mp1_exti_banks[] = { + &stm32mp1_exti_b1, + &stm32mp1_exti_b2, + &stm32mp1_exti_b3, +}; + +static const struct stm32_desc_irq stm32mp1_desc_irq[] = { + { .exti = 1, .irq_parent = 7 }, + { .exti = 2, .irq_parent = 8 }, + { .exti = 3, .irq_parent = 9 }, + { .exti = 4, .irq_parent = 10 }, + { .exti = 5, .irq_parent = 23 }, + { .exti = 6, .irq_parent = 64 }, + { .exti = 7, .irq_parent = 65 }, + { .exti = 8, .irq_parent = 66 }, + { .exti = 9, .irq_parent = 67 }, + { .exti = 10, .irq_parent = 40 }, + { .exti = 11, .irq_parent = 42 }, + { .exti = 12, .irq_parent = 76 }, + { .exti = 13, .irq_parent = 77 }, + { .exti = 14, .irq_parent = 121 }, + { .exti = 15, .irq_parent = 127 }, + { .exti = 16, .irq_parent = 1 }, + { .exti = 65, .irq_parent = 144 }, + { .exti = 68, .irq_parent = 143 }, + { .exti = 73, .irq_parent = 129 }, +}; + +static const struct stm32_exti_drv_data stm32mp1_drv_data = { + .exti_banks = stm32mp1_exti_banks, + .bank_nr = ARRAY_SIZE(stm32mp1_exti_banks), + .desc_irqs = stm32mp1_desc_irq, + .irq_nr = ARRAY_SIZE(stm32mp1_desc_irq), +}; + +static int stm32_exti_to_irq(const struct stm32_exti_drv_data *drv_data, + irq_hw_number_t hwirq) { - const struct stm32_exti_bank *stm32_bank = gc->private; + const struct stm32_desc_irq *desc_irq; + int i; - return irq_reg_readl(gc, stm32_bank->pr_ofst); + if (!drv_data->desc_irqs) + return -EINVAL; + + for (i = 0; i < drv_data->irq_nr; i++) { + desc_irq = &drv_data->desc_irqs[i]; + if (desc_irq->exti == hwirq) + return desc_irq->irq_parent; + } + + return -EINVAL; } -static void stm32_exti_irq_ack(struct irq_chip_generic *gc, u32 mask) +static unsigned long stm32_exti_pending(struct irq_chip_generic *gc) { - const struct stm32_exti_bank *stm32_bank = gc->private; + struct stm32_exti_chip_data *chip_data = gc->private; + const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; + unsigned long pending; + + pending = irq_reg_readl(gc, stm32_bank->rpr_ofst); + if (stm32_bank->fpr_ofst != UNDEF_REG) + pending |= irq_reg_readl(gc, stm32_bank->fpr_ofst); - irq_reg_writel(gc, mask, stm32_bank->pr_ofst); + return pending; } static void stm32_irq_handler(struct irq_desc *desc) @@ -92,7 +224,6 @@ static void stm32_irq_handler(struct irq_desc *desc) struct irq_chip *chip = irq_desc_get_chip(desc); unsigned int virq, nbanks = domain->gc->num_chips; struct irq_chip_generic *gc; - const struct stm32_exti_bank *stm32_bank; unsigned long pending; int n, i, irq_base = 0; @@ -100,13 +231,11 @@ static void stm32_irq_handler(struct irq_desc *desc) for (i = 0; i < nbanks; i++, irq_base += IRQS_PER_BANK) { gc = irq_get_domain_generic_chip(domain, irq_base); - stm32_bank = gc->private; while ((pending = stm32_exti_pending(gc))) { for_each_set_bit(n, &pending, IRQS_PER_BANK) { virq = irq_find_mapping(domain, irq_base + n); generic_handle_irq(virq); - stm32_exti_irq_ack(gc, BIT(n)); } } } @@ -114,36 +243,50 @@ static void stm32_irq_handler(struct irq_desc *desc) chained_irq_exit(chip, desc); } -static int stm32_irq_set_type(struct irq_data *data, unsigned int type) +static int stm32_exti_set_type(struct irq_data *d, + unsigned int type, u32 *rtsr, u32 *ftsr) { - struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); - const struct stm32_exti_bank *stm32_bank = gc->private; - int pin = data->hwirq % IRQS_PER_BANK; - u32 rtsr, ftsr; - - irq_gc_lock(gc); - - rtsr = irq_reg_readl(gc, stm32_bank->rtsr_ofst); - ftsr = irq_reg_readl(gc, stm32_bank->ftsr_ofst); + u32 mask = BIT(d->hwirq % IRQS_PER_BANK); switch (type) { case IRQ_TYPE_EDGE_RISING: - rtsr |= BIT(pin); - ftsr &= ~BIT(pin); + *rtsr |= mask; + *ftsr &= ~mask; break; case IRQ_TYPE_EDGE_FALLING: - rtsr &= ~BIT(pin); - ftsr |= BIT(pin); + *rtsr &= ~mask; + *ftsr |= mask; break; case IRQ_TYPE_EDGE_BOTH: - rtsr |= BIT(pin); - ftsr |= BIT(pin); + *rtsr |= mask; + *ftsr |= mask; break; default: - irq_gc_unlock(gc); return -EINVAL; } + return 0; +} + +static int stm32_irq_set_type(struct irq_data *d, unsigned int type) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct stm32_exti_chip_data *chip_data = gc->private; + const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; + u32 rtsr, ftsr; + int err; + + irq_gc_lock(gc); + + rtsr = irq_reg_readl(gc, stm32_bank->rtsr_ofst); + ftsr = irq_reg_readl(gc, stm32_bank->ftsr_ofst); + + err = stm32_exti_set_type(d, type, &rtsr, &ftsr); + if (err) { + irq_gc_unlock(gc); + return err; + } + irq_reg_writel(gc, rtsr, stm32_bank->rtsr_ofst); irq_reg_writel(gc, ftsr, stm32_bank->ftsr_ofst); @@ -152,40 +295,59 @@ static int stm32_irq_set_type(struct irq_data *data, unsigned int type) return 0; } -static int stm32_irq_set_wake(struct irq_data *data, unsigned int on) +static void stm32_chip_suspend(struct stm32_exti_chip_data *chip_data, + u32 wake_active) { - struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); - const struct stm32_exti_bank *stm32_bank = gc->private; - int pin = data->hwirq % IRQS_PER_BANK; - u32 imr; + const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; + void __iomem *base = chip_data->host_data->base; - irq_gc_lock(gc); + /* save rtsr, ftsr registers */ + chip_data->rtsr_cache = readl_relaxed(base + stm32_bank->rtsr_ofst); + chip_data->ftsr_cache = readl_relaxed(base + stm32_bank->ftsr_ofst); - imr = irq_reg_readl(gc, stm32_bank->imr_ofst); - if (on) - imr |= BIT(pin); - else - imr &= ~BIT(pin); - irq_reg_writel(gc, imr, stm32_bank->imr_ofst); + writel_relaxed(wake_active, base + stm32_bank->imr_ofst); +} + +static void stm32_chip_resume(struct stm32_exti_chip_data *chip_data, + u32 mask_cache) +{ + const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; + void __iomem *base = chip_data->host_data->base; + + /* restore rtsr, ftsr, registers */ + writel_relaxed(chip_data->rtsr_cache, base + stm32_bank->rtsr_ofst); + writel_relaxed(chip_data->ftsr_cache, base + stm32_bank->ftsr_ofst); + writel_relaxed(mask_cache, base + stm32_bank->imr_ofst); +} + +static void stm32_irq_suspend(struct irq_chip_generic *gc) +{ + struct stm32_exti_chip_data *chip_data = gc->private; + + irq_gc_lock(gc); + stm32_chip_suspend(chip_data, gc->wake_active); irq_gc_unlock(gc); +} - return 0; +static void stm32_irq_resume(struct irq_chip_generic *gc) +{ + struct stm32_exti_chip_data *chip_data = gc->private; + + irq_gc_lock(gc); + stm32_chip_resume(chip_data, gc->mask_cache); + irq_gc_unlock(gc); } static int stm32_exti_alloc(struct irq_domain *d, unsigned int virq, unsigned int nr_irqs, void *data) { - struct irq_chip_generic *gc; struct irq_fwspec *fwspec = data; irq_hw_number_t hwirq; hwirq = fwspec->param[0]; - gc = irq_get_domain_generic_chip(d, hwirq); irq_map_generic_chip(d, virq, hwirq); - irq_domain_set_info(d, virq, hwirq, &gc->chip_types->chip, gc, - handle_simple_irq, NULL, NULL); return 0; } @@ -198,30 +360,318 @@ static void stm32_exti_free(struct irq_domain *d, unsigned int virq, irq_domain_reset_irq_data(data); } -struct irq_domain_ops irq_exti_domain_ops = { +static const struct irq_domain_ops irq_exti_domain_ops = { .map = irq_map_generic_chip, - .xlate = irq_domain_xlate_onetwocell, .alloc = stm32_exti_alloc, .free = stm32_exti_free, }; -static int -__init stm32_exti_init(const struct stm32_exti_bank **stm32_exti_banks, - int bank_nr, struct device_node *node) +static void stm32_irq_ack(struct irq_data *d) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct stm32_exti_chip_data *chip_data = gc->private; + const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; + + irq_gc_lock(gc); + + irq_reg_writel(gc, d->mask, stm32_bank->rpr_ofst); + if (stm32_bank->fpr_ofst != UNDEF_REG) + irq_reg_writel(gc, d->mask, stm32_bank->fpr_ofst); + + irq_gc_unlock(gc); +} + +static inline u32 stm32_exti_set_bit(struct irq_data *d, u32 reg) { + struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); + void __iomem *base = chip_data->host_data->base; + u32 val; + + val = readl_relaxed(base + reg); + val |= BIT(d->hwirq % IRQS_PER_BANK); + writel_relaxed(val, base + reg); + + return val; +} + +static inline u32 stm32_exti_clr_bit(struct irq_data *d, u32 reg) +{ + struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); + void __iomem *base = chip_data->host_data->base; + u32 val; + + val = readl_relaxed(base + reg); + val &= ~BIT(d->hwirq % IRQS_PER_BANK); + writel_relaxed(val, base + reg); + + return val; +} + +static void stm32_exti_h_eoi(struct irq_data *d) +{ + struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); + const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; + + raw_spin_lock(&chip_data->rlock); + + stm32_exti_set_bit(d, stm32_bank->rpr_ofst); + if (stm32_bank->fpr_ofst != UNDEF_REG) + stm32_exti_set_bit(d, stm32_bank->fpr_ofst); + + raw_spin_unlock(&chip_data->rlock); + + if (d->parent_data->chip) + irq_chip_eoi_parent(d); +} + +static void stm32_exti_h_mask(struct irq_data *d) +{ + struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); + const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; + + raw_spin_lock(&chip_data->rlock); + chip_data->mask_cache = stm32_exti_clr_bit(d, stm32_bank->imr_ofst); + raw_spin_unlock(&chip_data->rlock); + + if (d->parent_data->chip) + irq_chip_mask_parent(d); +} + +static void stm32_exti_h_unmask(struct irq_data *d) +{ + struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); + const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; + + raw_spin_lock(&chip_data->rlock); + chip_data->mask_cache = stm32_exti_set_bit(d, stm32_bank->imr_ofst); + raw_spin_unlock(&chip_data->rlock); + + if (d->parent_data->chip) + irq_chip_unmask_parent(d); +} + +static int stm32_exti_h_set_type(struct irq_data *d, unsigned int type) +{ + struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); + const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; + void __iomem *base = chip_data->host_data->base; + u32 rtsr, ftsr; + int err; + + raw_spin_lock(&chip_data->rlock); + rtsr = readl_relaxed(base + stm32_bank->rtsr_ofst); + ftsr = readl_relaxed(base + stm32_bank->ftsr_ofst); + + err = stm32_exti_set_type(d, type, &rtsr, &ftsr); + if (err) { + raw_spin_unlock(&chip_data->rlock); + return err; + } + + writel_relaxed(rtsr, base + stm32_bank->rtsr_ofst); + writel_relaxed(ftsr, base + stm32_bank->ftsr_ofst); + raw_spin_unlock(&chip_data->rlock); + + return 0; +} + +static int stm32_exti_h_set_wake(struct irq_data *d, unsigned int on) +{ + struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); + u32 mask = BIT(d->hwirq % IRQS_PER_BANK); + + raw_spin_lock(&chip_data->rlock); + + if (on) + chip_data->wake_active |= mask; + else + chip_data->wake_active &= ~mask; + + raw_spin_unlock(&chip_data->rlock); + + return 0; +} + +static int stm32_exti_h_set_affinity(struct irq_data *d, + const struct cpumask *dest, bool force) +{ + if (d->parent_data->chip) + return irq_chip_set_affinity_parent(d, dest, force); + + return -EINVAL; +} + +#ifdef CONFIG_PM +static int stm32_exti_h_suspend(void) +{ + struct stm32_exti_chip_data *chip_data; + int i; + + for (i = 0; i < stm32_host_data->drv_data->bank_nr; i++) { + chip_data = &stm32_host_data->chips_data[i]; + raw_spin_lock(&chip_data->rlock); + stm32_chip_suspend(chip_data, chip_data->wake_active); + raw_spin_unlock(&chip_data->rlock); + } + + return 0; +} + +static void stm32_exti_h_resume(void) +{ + struct stm32_exti_chip_data *chip_data; + int i; + + for (i = 0; i < stm32_host_data->drv_data->bank_nr; i++) { + chip_data = &stm32_host_data->chips_data[i]; + raw_spin_lock(&chip_data->rlock); + stm32_chip_resume(chip_data, chip_data->mask_cache); + raw_spin_unlock(&chip_data->rlock); + } +} + +static struct syscore_ops stm32_exti_h_syscore_ops = { + .suspend = stm32_exti_h_suspend, + .resume = stm32_exti_h_resume, +}; + +static void stm32_exti_h_syscore_init(void) +{ + register_syscore_ops(&stm32_exti_h_syscore_ops); +} +#else +static inline void stm32_exti_h_syscore_init(void) {} +#endif + +static struct irq_chip stm32_exti_h_chip = { + .name = "stm32-exti-h", + .irq_eoi = stm32_exti_h_eoi, + .irq_mask = stm32_exti_h_mask, + .irq_unmask = stm32_exti_h_unmask, + .irq_retrigger = irq_chip_retrigger_hierarchy, + .irq_set_type = stm32_exti_h_set_type, + .irq_set_wake = stm32_exti_h_set_wake, + .flags = IRQCHIP_MASK_ON_SUSPEND, +#ifdef CONFIG_SMP + .irq_set_affinity = stm32_exti_h_set_affinity, +#endif +}; + +static int stm32_exti_h_domain_alloc(struct irq_domain *dm, + unsigned int virq, + unsigned int nr_irqs, void *data) +{ + struct stm32_exti_host_data *host_data = dm->host_data; + struct stm32_exti_chip_data *chip_data; + struct irq_fwspec *fwspec = data; + struct irq_fwspec p_fwspec; + irq_hw_number_t hwirq; + int p_irq, bank; + + hwirq = fwspec->param[0]; + bank = hwirq / IRQS_PER_BANK; + chip_data = &host_data->chips_data[bank]; + + irq_domain_set_hwirq_and_chip(dm, virq, hwirq, + &stm32_exti_h_chip, chip_data); + + p_irq = stm32_exti_to_irq(host_data->drv_data, hwirq); + if (p_irq >= 0) { + p_fwspec.fwnode = dm->parent->fwnode; + p_fwspec.param_count = 3; + p_fwspec.param[0] = GIC_SPI; + p_fwspec.param[1] = p_irq; + p_fwspec.param[2] = IRQ_TYPE_LEVEL_HIGH; + + return irq_domain_alloc_irqs_parent(dm, virq, 1, &p_fwspec); + } + + return 0; +} + +static struct +stm32_exti_host_data *stm32_exti_host_init(const struct stm32_exti_drv_data *dd, + struct device_node *node) +{ + struct stm32_exti_host_data *host_data; + + host_data = kzalloc(sizeof(*host_data), GFP_KERNEL); + if (!host_data) + return NULL; + + host_data->drv_data = dd; + host_data->chips_data = kcalloc(dd->bank_nr, + sizeof(struct stm32_exti_chip_data), + GFP_KERNEL); + if (!host_data->chips_data) + return NULL; + + host_data->base = of_iomap(node, 0); + if (!host_data->base) { + pr_err("%pOF: Unable to map registers\n", node); + return NULL; + } + + stm32_host_data = host_data; + + return host_data; +} + +static struct +stm32_exti_chip_data *stm32_exti_chip_init(struct stm32_exti_host_data *h_data, + u32 bank_idx, + struct device_node *node) +{ + const struct stm32_exti_bank *stm32_bank; + struct stm32_exti_chip_data *chip_data; + void __iomem *base = h_data->base; + u32 irqs_mask; + + stm32_bank = h_data->drv_data->exti_banks[bank_idx]; + chip_data = &h_data->chips_data[bank_idx]; + chip_data->host_data = h_data; + chip_data->reg_bank = stm32_bank; + + raw_spin_lock_init(&chip_data->rlock); + + /* Determine number of irqs supported */ + writel_relaxed(~0UL, base + stm32_bank->rtsr_ofst); + irqs_mask = readl_relaxed(base + stm32_bank->rtsr_ofst); + + /* + * This IP has no reset, so after hot reboot we should + * clear registers to avoid residue + */ + writel_relaxed(0, base + stm32_bank->imr_ofst); + writel_relaxed(0, base + stm32_bank->emr_ofst); + writel_relaxed(0, base + stm32_bank->rtsr_ofst); + writel_relaxed(0, base + stm32_bank->ftsr_ofst); + writel_relaxed(~0UL, base + stm32_bank->rpr_ofst); + if (stm32_bank->fpr_ofst != UNDEF_REG) + writel_relaxed(~0UL, base + stm32_bank->fpr_ofst); + + pr_info("%s: bank%d, External IRQs available:%#x\n", + node->full_name, bank_idx, irqs_mask); + + return chip_data; +} + +static int __init stm32_exti_init(const struct stm32_exti_drv_data *drv_data, + struct device_node *node) +{ + struct stm32_exti_host_data *host_data; unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; - int nr_irqs, nr_exti, ret, i; + int nr_irqs, ret, i; struct irq_chip_generic *gc; struct irq_domain *domain; - void *base; - base = of_iomap(node, 0); - if (!base) { - pr_err("%pOF: Unable to map registers\n", node); - return -ENOMEM; + host_data = stm32_exti_host_init(drv_data, node); + if (!host_data) { + ret = -ENOMEM; + goto out_free_mem; } - domain = irq_domain_add_linear(node, bank_nr * IRQS_PER_BANK, + domain = irq_domain_add_linear(node, drv_data->bank_nr * IRQS_PER_BANK, &irq_exti_domain_ops, NULL); if (!domain) { pr_err("%s: Could not register interrupt domain.\n", @@ -234,44 +684,32 @@ __init stm32_exti_init(const struct stm32_exti_bank **stm32_exti_banks, handle_edge_irq, clr, 0, 0); if (ret) { pr_err("%pOF: Could not allocate generic interrupt chip.\n", - node); + node); goto out_free_domain; } - for (i = 0; i < bank_nr; i++) { - const struct stm32_exti_bank *stm32_bank = stm32_exti_banks[i]; - u32 irqs_mask; + for (i = 0; i < drv_data->bank_nr; i++) { + const struct stm32_exti_bank *stm32_bank; + struct stm32_exti_chip_data *chip_data; + + stm32_bank = drv_data->exti_banks[i]; + chip_data = stm32_exti_chip_init(host_data, i, node); gc = irq_get_domain_generic_chip(domain, i * IRQS_PER_BANK); - gc->reg_base = base; + gc->reg_base = host_data->base; gc->chip_types->type = IRQ_TYPE_EDGE_BOTH; - gc->chip_types->chip.irq_ack = irq_gc_ack_set_bit; + gc->chip_types->chip.irq_ack = stm32_irq_ack; gc->chip_types->chip.irq_mask = irq_gc_mask_clr_bit; gc->chip_types->chip.irq_unmask = irq_gc_mask_set_bit; gc->chip_types->chip.irq_set_type = stm32_irq_set_type; - gc->chip_types->chip.irq_set_wake = stm32_irq_set_wake; - gc->chip_types->regs.ack = stm32_bank->pr_ofst; + gc->chip_types->chip.irq_set_wake = irq_gc_set_wake; + gc->suspend = stm32_irq_suspend; + gc->resume = stm32_irq_resume; + gc->wake_enabled = IRQ_MSK(IRQS_PER_BANK); + gc->chip_types->regs.mask = stm32_bank->imr_ofst; - gc->private = (void *)stm32_bank; - - /* Determine number of irqs supported */ - writel_relaxed(~0UL, base + stm32_bank->rtsr_ofst); - irqs_mask = readl_relaxed(base + stm32_bank->rtsr_ofst); - nr_exti = fls(readl_relaxed(base + stm32_bank->rtsr_ofst)); - - /* - * This IP has no reset, so after hot reboot we should - * clear registers to avoid residue - */ - writel_relaxed(0, base + stm32_bank->imr_ofst); - writel_relaxed(0, base + stm32_bank->emr_ofst); - writel_relaxed(0, base + stm32_bank->rtsr_ofst); - writel_relaxed(0, base + stm32_bank->ftsr_ofst); - writel_relaxed(~0UL, base + stm32_bank->pr_ofst); - - pr_info("%s: bank%d, External IRQs available:%#x\n", - node->full_name, i, irqs_mask); + gc->private = (void *)chip_data; } nr_irqs = of_irq_count(node); @@ -287,15 +725,69 @@ __init stm32_exti_init(const struct stm32_exti_bank **stm32_exti_banks, out_free_domain: irq_domain_remove(domain); out_unmap: - iounmap(base); + iounmap(host_data->base); +out_free_mem: + kfree(host_data->chips_data); + kfree(host_data); + return ret; +} + +static const struct irq_domain_ops stm32_exti_h_domain_ops = { + .alloc = stm32_exti_h_domain_alloc, + .free = irq_domain_free_irqs_common, +}; + +static int +__init stm32_exti_hierarchy_init(const struct stm32_exti_drv_data *drv_data, + struct device_node *node, + struct device_node *parent) +{ + struct irq_domain *parent_domain, *domain; + struct stm32_exti_host_data *host_data; + int ret, i; + + parent_domain = irq_find_host(parent); + if (!parent_domain) { + pr_err("interrupt-parent not found\n"); + return -EINVAL; + } + + host_data = stm32_exti_host_init(drv_data, node); + if (!host_data) { + ret = -ENOMEM; + goto out_free_mem; + } + + for (i = 0; i < drv_data->bank_nr; i++) + stm32_exti_chip_init(host_data, i, node); + + domain = irq_domain_add_hierarchy(parent_domain, 0, + drv_data->bank_nr * IRQS_PER_BANK, + node, &stm32_exti_h_domain_ops, + host_data); + + if (!domain) { + pr_err("%s: Could not register exti domain.\n", node->name); + ret = -ENOMEM; + goto out_unmap; + } + + stm32_exti_h_syscore_init(); + + return 0; + +out_unmap: + iounmap(host_data->base); +out_free_mem: + kfree(host_data->chips_data); + kfree(host_data); return ret; } static int __init stm32f4_exti_of_init(struct device_node *np, struct device_node *parent) { - return stm32_exti_init(stm32f4xx_exti_banks, - ARRAY_SIZE(stm32f4xx_exti_banks), np); + return stm32_exti_init(&stm32f4xx_drv_data, np); } IRQCHIP_DECLARE(stm32f4_exti, "st,stm32-exti", stm32f4_exti_of_init); @@ -303,8 +795,15 @@ IRQCHIP_DECLARE(stm32f4_exti, "st,stm32-exti", stm32f4_exti_of_init); static int __init stm32h7_exti_of_init(struct device_node *np, struct device_node *parent) { - return stm32_exti_init(stm32h7xx_exti_banks, - ARRAY_SIZE(stm32h7xx_exti_banks), np); + return stm32_exti_init(&stm32h7xx_drv_data, np); } IRQCHIP_DECLARE(stm32h7_exti, "st,stm32h7-exti", stm32h7_exti_of_init); + +static int __init stm32mp1_exti_of_init(struct device_node *np, + struct device_node *parent) +{ + return stm32_exti_hierarchy_init(&stm32mp1_drv_data, np, parent); +} + +IRQCHIP_DECLARE(stm32mp1_exti, "st,stm32mp1-exti", stm32mp1_exti_of_init); diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index 19cd93783c87..baa1ee2bc2ac 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -1340,19 +1340,6 @@ static int capi20_proc_show(struct seq_file *m, void *v) return 0; } -static int capi20_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, capi20_proc_show, NULL); -} - -static const struct file_operations capi20_proc_fops = { - .owner = THIS_MODULE, - .open = capi20_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - /* * /proc/capi/capi20ncci: * applid ncci @@ -1373,23 +1360,10 @@ static int capi20ncci_proc_show(struct seq_file *m, void *v) return 0; } -static int capi20ncci_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, capi20ncci_proc_show, NULL); -} - -static const struct file_operations capi20ncci_proc_fops = { - .owner = THIS_MODULE, - .open = capi20ncci_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static void __init proc_init(void) { - proc_create("capi/capi20", 0, NULL, &capi20_proc_fops); - proc_create("capi/capi20ncci", 0, NULL, &capi20ncci_proc_fops); + proc_create_single("capi/capi20", 0, NULL, capi20_proc_show); + proc_create_single("capi/capi20ncci", 0, NULL, capi20ncci_proc_show); } static void __exit proc_exit(void) diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c index 49fef08858c5..7ac51798949d 100644 --- a/drivers/isdn/capi/capidrv.c +++ b/drivers/isdn/capi/capidrv.c @@ -2460,22 +2460,9 @@ static int capidrv_proc_show(struct seq_file *m, void *v) return 0; } -static int capidrv_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, capidrv_proc_show, NULL); -} - -static const struct file_operations capidrv_proc_fops = { - .owner = THIS_MODULE, - .open = capidrv_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static void __init proc_init(void) { - proc_create("capi/capidrv", 0, NULL, &capidrv_proc_fops); + proc_create_single("capi/capidrv", 0, NULL, capidrv_proc_show); } static void __exit proc_exit(void) diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c index 46c189ad8d94..0ff517d3c98f 100644 --- a/drivers/isdn/capi/kcapi.c +++ b/drivers/isdn/capi/kcapi.c @@ -534,7 +534,8 @@ int attach_capi_ctr(struct capi_ctr *ctr) init_waitqueue_head(&ctr->state_wait_queue); sprintf(ctr->procfn, "capi/controllers/%d", ctr->cnr); - ctr->procent = proc_create_data(ctr->procfn, 0, NULL, ctr->proc_fops, ctr); + ctr->procent = proc_create_single_data(ctr->procfn, 0, NULL, + ctr->proc_show, ctr); ncontrollers++; diff --git a/drivers/isdn/capi/kcapi_proc.c b/drivers/isdn/capi/kcapi_proc.c index 68db3c5a1063..c94bd12c0f7c 100644 --- a/drivers/isdn/capi/kcapi_proc.c +++ b/drivers/isdn/capi/kcapi_proc.c @@ -108,32 +108,6 @@ static const struct seq_operations seq_contrstats_ops = { .show = contrstats_show, }; -static int seq_controller_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &seq_controller_ops); -} - -static int seq_contrstats_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &seq_contrstats_ops); -} - -static const struct file_operations proc_controller_ops = { - .owner = THIS_MODULE, - .open = seq_controller_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -static const struct file_operations proc_contrstats_ops = { - .owner = THIS_MODULE, - .open = seq_contrstats_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - // /proc/capi/applications: // applid l3cnt dblkcnt dblklen #ncci recvqueuelen // /proc/capi/applstats: @@ -216,34 +190,6 @@ static const struct seq_operations seq_applstats_ops = { .show = applstats_show, }; -static int -seq_applications_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &seq_applications_ops); -} - -static int -seq_applstats_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &seq_applstats_ops); -} - -static const struct file_operations proc_applications_ops = { - .owner = THIS_MODULE, - .open = seq_applications_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -static const struct file_operations proc_applstats_ops = { - .owner = THIS_MODULE, - .open = seq_applstats_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - // --------------------------------------------------------------------------- static void *capi_driver_start(struct seq_file *seq, loff_t *pos) @@ -279,22 +225,6 @@ static const struct seq_operations seq_capi_driver_ops = { .show = capi_driver_show, }; -static int -seq_capi_driver_open(struct inode *inode, struct file *file) -{ - int err; - err = seq_open(file, &seq_capi_driver_ops); - return err; -} - -static const struct file_operations proc_driver_ops = { - .owner = THIS_MODULE, - .open = seq_capi_driver_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - // --------------------------------------------------------------------------- void __init @@ -302,11 +232,11 @@ kcapi_proc_init(void) { proc_mkdir("capi", NULL); proc_mkdir("capi/controllers", NULL); - proc_create("capi/controller", 0, NULL, &proc_controller_ops); - proc_create("capi/contrstats", 0, NULL, &proc_contrstats_ops); - proc_create("capi/applications", 0, NULL, &proc_applications_ops); - proc_create("capi/applstats", 0, NULL, &proc_applstats_ops); - proc_create("capi/driver", 0, NULL, &proc_driver_ops); + proc_create_seq("capi/controller", 0, NULL, &seq_controller_ops); + proc_create_seq("capi/contrstats", 0, NULL, &seq_contrstats_ops); + proc_create_seq("capi/applications", 0, NULL, &seq_applications_ops); + proc_create_seq("capi/applstats", 0, NULL, &seq_applstats_ops); + proc_create_seq("capi/driver", 0, NULL, &seq_capi_driver_ops); } void __exit diff --git a/drivers/isdn/gigaset/capi.c b/drivers/isdn/gigaset/capi.c index ccec7778cad2..56748af78c04 100644 --- a/drivers/isdn/gigaset/capi.c +++ b/drivers/isdn/gigaset/capi.c @@ -2437,19 +2437,6 @@ static int gigaset_proc_show(struct seq_file *m, void *v) return 0; } -static int gigaset_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, gigaset_proc_show, PDE_DATA(inode)); -} - -static const struct file_operations gigaset_proc_fops = { - .owner = THIS_MODULE, - .open = gigaset_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - /** * gigaset_isdn_regdev() - register device to LL * @cs: device descriptor structure. @@ -2479,7 +2466,7 @@ int gigaset_isdn_regdev(struct cardstate *cs, const char *isdnid) iif->ctr.release_appl = gigaset_release_appl; iif->ctr.send_message = gigaset_send_message; iif->ctr.procinfo = gigaset_procinfo; - iif->ctr.proc_fops = &gigaset_proc_fops; + iif->ctr.proc_show = gigaset_proc_show, INIT_LIST_HEAD(&iif->appls); skb_queue_head_init(&iif->sendqueue); atomic_set(&iif->sendqlen, 0); diff --git a/drivers/isdn/hardware/avm/avmcard.h b/drivers/isdn/hardware/avm/avmcard.h index c95712dbfa9f..cdfa89c71997 100644 --- a/drivers/isdn/hardware/avm/avmcard.h +++ b/drivers/isdn/hardware/avm/avmcard.h @@ -556,7 +556,7 @@ u16 b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb); void b1_parse_version(avmctrl_info *card); irqreturn_t b1_interrupt(int interrupt, void *devptr); -extern const struct file_operations b1ctl_proc_fops; +int b1_proc_show(struct seq_file *m, void *v); avmcard_dmainfo *avmcard_dma_alloc(char *name, struct pci_dev *, long rsize, long ssize); @@ -576,6 +576,6 @@ void b1dma_register_appl(struct capi_ctr *ctrl, capi_register_params *rp); void b1dma_release_appl(struct capi_ctr *ctrl, u16 appl); u16 b1dma_send_message(struct capi_ctr *ctrl, struct sk_buff *skb); -extern const struct file_operations b1dmactl_proc_fops; +int b1dma_proc_show(struct seq_file *m, void *v); #endif /* _AVMCARD_H_ */ diff --git a/drivers/isdn/hardware/avm/b1.c b/drivers/isdn/hardware/avm/b1.c index b1833d08a5fe..5ee5489d3f15 100644 --- a/drivers/isdn/hardware/avm/b1.c +++ b/drivers/isdn/hardware/avm/b1.c @@ -637,7 +637,7 @@ irqreturn_t b1_interrupt(int interrupt, void *devptr) } /* ------------------------------------------------------------- */ -static int b1ctl_proc_show(struct seq_file *m, void *v) +int b1_proc_show(struct seq_file *m, void *v) { struct capi_ctr *ctrl = m->private; avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); @@ -699,20 +699,7 @@ static int b1ctl_proc_show(struct seq_file *m, void *v) return 0; } - -static int b1ctl_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, b1ctl_proc_show, PDE_DATA(inode)); -} - -const struct file_operations b1ctl_proc_fops = { - .owner = THIS_MODULE, - .open = b1ctl_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; -EXPORT_SYMBOL(b1ctl_proc_fops); +EXPORT_SYMBOL(b1_proc_show); /* ------------------------------------------------------------- */ diff --git a/drivers/isdn/hardware/avm/b1dma.c b/drivers/isdn/hardware/avm/b1dma.c index 9538a9e5e1a8..6a3dc9937ce5 100644 --- a/drivers/isdn/hardware/avm/b1dma.c +++ b/drivers/isdn/hardware/avm/b1dma.c @@ -858,7 +858,7 @@ u16 b1dma_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) /* ------------------------------------------------------------- */ -static int b1dmactl_proc_show(struct seq_file *m, void *v) +int b1dma_proc_show(struct seq_file *m, void *v) { struct capi_ctr *ctrl = m->private; avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); @@ -941,20 +941,7 @@ static int b1dmactl_proc_show(struct seq_file *m, void *v) return 0; } - -static int b1dmactl_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, b1dmactl_proc_show, PDE_DATA(inode)); -} - -const struct file_operations b1dmactl_proc_fops = { - .owner = THIS_MODULE, - .open = b1dmactl_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; -EXPORT_SYMBOL(b1dmactl_proc_fops); +EXPORT_SYMBOL(b1dma_proc_show); /* ------------------------------------------------------------- */ diff --git a/drivers/isdn/hardware/avm/b1isa.c b/drivers/isdn/hardware/avm/b1isa.c index 54e871a47387..cdfea72e0ef6 100644 --- a/drivers/isdn/hardware/avm/b1isa.c +++ b/drivers/isdn/hardware/avm/b1isa.c @@ -121,7 +121,7 @@ static int b1isa_probe(struct pci_dev *pdev) cinfo->capi_ctrl.load_firmware = b1_load_firmware; cinfo->capi_ctrl.reset_ctr = b1_reset_ctr; cinfo->capi_ctrl.procinfo = b1isa_procinfo; - cinfo->capi_ctrl.proc_fops = &b1ctl_proc_fops; + cinfo->capi_ctrl.proc_show = b1_proc_show; strcpy(cinfo->capi_ctrl.name, card->name); retval = attach_capi_ctr(&cinfo->capi_ctrl); diff --git a/drivers/isdn/hardware/avm/b1pci.c b/drivers/isdn/hardware/avm/b1pci.c index ac4863c2ecbc..b76b57a82c02 100644 --- a/drivers/isdn/hardware/avm/b1pci.c +++ b/drivers/isdn/hardware/avm/b1pci.c @@ -112,7 +112,7 @@ static int b1pci_probe(struct capicardparams *p, struct pci_dev *pdev) cinfo->capi_ctrl.load_firmware = b1_load_firmware; cinfo->capi_ctrl.reset_ctr = b1_reset_ctr; cinfo->capi_ctrl.procinfo = b1pci_procinfo; - cinfo->capi_ctrl.proc_fops = &b1ctl_proc_fops; + cinfo->capi_ctrl.proc_show = b1_proc_show; strcpy(cinfo->capi_ctrl.name, card->name); cinfo->capi_ctrl.owner = THIS_MODULE; @@ -251,7 +251,7 @@ static int b1pciv4_probe(struct capicardparams *p, struct pci_dev *pdev) cinfo->capi_ctrl.load_firmware = b1dma_load_firmware; cinfo->capi_ctrl.reset_ctr = b1dma_reset_ctr; cinfo->capi_ctrl.procinfo = b1pciv4_procinfo; - cinfo->capi_ctrl.proc_fops = &b1dmactl_proc_fops; + cinfo->capi_ctrl.proc_show = b1dma_proc_show; strcpy(cinfo->capi_ctrl.name, card->name); retval = attach_capi_ctr(&cinfo->capi_ctrl); diff --git a/drivers/isdn/hardware/avm/b1pcmcia.c b/drivers/isdn/hardware/avm/b1pcmcia.c index 6b0d19d963d5..3aca16e62902 100644 --- a/drivers/isdn/hardware/avm/b1pcmcia.c +++ b/drivers/isdn/hardware/avm/b1pcmcia.c @@ -108,7 +108,7 @@ static int b1pcmcia_add_card(unsigned int port, unsigned irq, cinfo->capi_ctrl.load_firmware = b1_load_firmware; cinfo->capi_ctrl.reset_ctr = b1_reset_ctr; cinfo->capi_ctrl.procinfo = b1pcmcia_procinfo; - cinfo->capi_ctrl.proc_fops = &b1ctl_proc_fops; + cinfo->capi_ctrl.proc_show = b1_proc_show; strcpy(cinfo->capi_ctrl.name, card->name); retval = attach_capi_ctr(&cinfo->capi_ctrl); diff --git a/drivers/isdn/hardware/avm/c4.c b/drivers/isdn/hardware/avm/c4.c index 034cabac699d..ac72cd204c4d 100644 --- a/drivers/isdn/hardware/avm/c4.c +++ b/drivers/isdn/hardware/avm/c4.c @@ -1127,19 +1127,6 @@ static int c4_proc_show(struct seq_file *m, void *v) return 0; } -static int c4_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, c4_proc_show, PDE_DATA(inode)); -} - -static const struct file_operations c4_proc_fops = { - .owner = THIS_MODULE, - .open = c4_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - /* ------------------------------------------------------------- */ static int c4_add_card(struct capicardparams *p, struct pci_dev *dev, @@ -1211,7 +1198,7 @@ static int c4_add_card(struct capicardparams *p, struct pci_dev *dev, cinfo->capi_ctrl.load_firmware = c4_load_firmware; cinfo->capi_ctrl.reset_ctr = c4_reset_ctr; cinfo->capi_ctrl.procinfo = c4_procinfo; - cinfo->capi_ctrl.proc_fops = &c4_proc_fops; + cinfo->capi_ctrl.proc_show = c4_proc_show; strcpy(cinfo->capi_ctrl.name, card->name); retval = attach_capi_ctr(&cinfo->capi_ctrl); diff --git a/drivers/isdn/hardware/avm/t1isa.c b/drivers/isdn/hardware/avm/t1isa.c index 9f80d20ced87..2153619c5b31 100644 --- a/drivers/isdn/hardware/avm/t1isa.c +++ b/drivers/isdn/hardware/avm/t1isa.c @@ -430,7 +430,7 @@ static int t1isa_probe(struct pci_dev *pdev, int cardnr) cinfo->capi_ctrl.load_firmware = t1isa_load_firmware; cinfo->capi_ctrl.reset_ctr = t1isa_reset_ctr; cinfo->capi_ctrl.procinfo = t1isa_procinfo; - cinfo->capi_ctrl.proc_fops = &b1ctl_proc_fops; + cinfo->capi_ctrl.proc_show = b1_proc_show; strcpy(cinfo->capi_ctrl.name, card->name); retval = attach_capi_ctr(&cinfo->capi_ctrl); diff --git a/drivers/isdn/hardware/avm/t1pci.c b/drivers/isdn/hardware/avm/t1pci.c index 2180b1685691..f5ed1d5004c9 100644 --- a/drivers/isdn/hardware/avm/t1pci.c +++ b/drivers/isdn/hardware/avm/t1pci.c @@ -119,7 +119,7 @@ static int t1pci_add_card(struct capicardparams *p, struct pci_dev *pdev) cinfo->capi_ctrl.load_firmware = b1dma_load_firmware; cinfo->capi_ctrl.reset_ctr = b1dma_reset_ctr; cinfo->capi_ctrl.procinfo = t1pci_procinfo; - cinfo->capi_ctrl.proc_fops = &b1dmactl_proc_fops; + cinfo->capi_ctrl.proc_show = b1dma_proc_show; strcpy(cinfo->capi_ctrl.name, card->name); retval = attach_capi_ctr(&cinfo->capi_ctrl); diff --git a/drivers/isdn/hardware/eicon/capimain.c b/drivers/isdn/hardware/eicon/capimain.c index be36d82004d6..f9244dc1c3c9 100644 --- a/drivers/isdn/hardware/eicon/capimain.c +++ b/drivers/isdn/hardware/eicon/capimain.c @@ -90,19 +90,6 @@ static int diva_ctl_proc_show(struct seq_file *m, void *v) return 0; } -static int diva_ctl_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, diva_ctl_proc_show, NULL); -} - -static const struct file_operations diva_ctl_proc_fops = { - .owner = THIS_MODULE, - .open = diva_ctl_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - /* * set additional os settings in capi_ctr struct */ @@ -111,7 +98,7 @@ void diva_os_set_controller_struct(struct capi_ctr *ctrl) ctrl->driver_name = DRIVERLNAME; ctrl->load_firmware = NULL; ctrl->reset_ctr = NULL; - ctrl->proc_fops = &diva_ctl_proc_fops; + ctrl->proc_show = diva_ctl_proc_show; ctrl->owner = THIS_MODULE; } diff --git a/drivers/isdn/hardware/eicon/diva.c b/drivers/isdn/hardware/eicon/diva.c index 944a7f338099..1b25d8bc153a 100644 --- a/drivers/isdn/hardware/eicon/diva.c +++ b/drivers/isdn/hardware/eicon/diva.c @@ -388,10 +388,10 @@ void divasa_xdi_driver_unload(void) ** Receive and process command from user mode utility */ void *diva_xdi_open_adapter(void *os_handle, const void __user *src, - int length, + int length, void *mptr, divas_xdi_copy_from_user_fn_t cp_fn) { - diva_xdi_um_cfg_cmd_t msg; + diva_xdi_um_cfg_cmd_t *msg = (diva_xdi_um_cfg_cmd_t *)mptr; diva_os_xdi_adapter_t *a = NULL; diva_os_spin_lock_magic_t old_irql; struct list_head *tmp; @@ -401,21 +401,21 @@ void *diva_xdi_open_adapter(void *os_handle, const void __user *src, length, sizeof(diva_xdi_um_cfg_cmd_t))) return NULL; } - if ((*cp_fn) (os_handle, &msg, src, sizeof(msg)) <= 0) { + if ((*cp_fn) (os_handle, msg, src, sizeof(*msg)) <= 0) { DBG_ERR(("A: A(?) open, write error")) return NULL; } diva_os_enter_spin_lock(&adapter_lock, &old_irql, "open_adapter"); list_for_each(tmp, &adapter_queue) { a = list_entry(tmp, diva_os_xdi_adapter_t, link); - if (a->controller == (int)msg.adapter) + if (a->controller == (int)msg->adapter) break; a = NULL; } diva_os_leave_spin_lock(&adapter_lock, &old_irql, "open_adapter"); if (!a) { - DBG_ERR(("A: A(%d) open, adapter not found", msg.adapter)) + DBG_ERR(("A: A(%d) open, adapter not found", msg->adapter)) } return (a); @@ -437,8 +437,10 @@ void diva_xdi_close_adapter(void *adapter, void *os_handle) int diva_xdi_write(void *adapter, void *os_handle, const void __user *src, - int length, divas_xdi_copy_from_user_fn_t cp_fn) + int length, void *mptr, + divas_xdi_copy_from_user_fn_t cp_fn) { + diva_xdi_um_cfg_cmd_t *msg = (diva_xdi_um_cfg_cmd_t *)mptr; diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) adapter; void *data; @@ -459,7 +461,13 @@ diva_xdi_write(void *adapter, void *os_handle, const void __user *src, return (-2); } - length = (*cp_fn) (os_handle, data, src, length); + if (msg) { + *(diva_xdi_um_cfg_cmd_t *)data = *msg; + length = (*cp_fn) (os_handle, (char *)data + sizeof(*msg), + src + sizeof(*msg), length - sizeof(*msg)); + } else { + length = (*cp_fn) (os_handle, data, src, length); + } if (length > 0) { if ((*(a->interface.cmd_proc)) (a, (diva_xdi_um_cfg_cmd_t *) data, length)) { diff --git a/drivers/isdn/hardware/eicon/diva.h b/drivers/isdn/hardware/eicon/diva.h index b067032093a8..1ad76650fbf9 100644 --- a/drivers/isdn/hardware/eicon/diva.h +++ b/drivers/isdn/hardware/eicon/diva.h @@ -20,10 +20,11 @@ int diva_xdi_read(void *adapter, void *os_handle, void __user *dst, int max_length, divas_xdi_copy_to_user_fn_t cp_fn); int diva_xdi_write(void *adapter, void *os_handle, const void __user *src, - int length, divas_xdi_copy_from_user_fn_t cp_fn); + int length, void *msg, + divas_xdi_copy_from_user_fn_t cp_fn); void *diva_xdi_open_adapter(void *os_handle, const void __user *src, - int length, + int length, void *msg, divas_xdi_copy_from_user_fn_t cp_fn); void diva_xdi_close_adapter(void *adapter, void *os_handle); diff --git a/drivers/isdn/hardware/eicon/diva_didd.c b/drivers/isdn/hardware/eicon/diva_didd.c index fab6ccfb00d5..60e79257dd5f 100644 --- a/drivers/isdn/hardware/eicon/diva_didd.c +++ b/drivers/isdn/hardware/eicon/diva_didd.c @@ -78,26 +78,13 @@ static int divadidd_proc_show(struct seq_file *m, void *v) return 0; } -static int divadidd_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, divadidd_proc_show, NULL); -} - -static const struct file_operations divadidd_proc_fops = { - .owner = THIS_MODULE, - .open = divadidd_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static int __init create_proc(void) { proc_net_eicon = proc_mkdir("eicon", init_net.proc_net); if (proc_net_eicon) { - proc_didd = proc_create(DRIVERLNAME, S_IRUGO, proc_net_eicon, - &divadidd_proc_fops); + proc_didd = proc_create_single(DRIVERLNAME, S_IRUGO, + proc_net_eicon, divadidd_proc_show); return (1); } return (0); diff --git a/drivers/isdn/hardware/eicon/divasi.c b/drivers/isdn/hardware/eicon/divasi.c index 525518c945fe..e7081e0c0e35 100644 --- a/drivers/isdn/hardware/eicon/divasi.c +++ b/drivers/isdn/hardware/eicon/divasi.c @@ -101,23 +101,10 @@ static int um_idi_proc_show(struct seq_file *m, void *v) return 0; } -static int um_idi_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, um_idi_proc_show, NULL); -} - -static const struct file_operations um_idi_proc_fops = { - .owner = THIS_MODULE, - .open = um_idi_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static int __init create_um_idi_proc(void) { - um_idi_proc_entry = proc_create(DRIVERLNAME, S_IRUGO, proc_net_eicon, - &um_idi_proc_fops); + um_idi_proc_entry = proc_create_single(DRIVERLNAME, S_IRUGO, + proc_net_eicon, um_idi_proc_show); if (!um_idi_proc_entry) return (0); return (1); diff --git a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c index b9980e84f9db..b6a3950b2564 100644 --- a/drivers/isdn/hardware/eicon/divasmain.c +++ b/drivers/isdn/hardware/eicon/divasmain.c @@ -591,19 +591,22 @@ static int divas_release(struct inode *inode, struct file *file) static ssize_t divas_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { + diva_xdi_um_cfg_cmd_t msg; int ret = -EINVAL; if (!file->private_data) { file->private_data = diva_xdi_open_adapter(file, buf, - count, + count, &msg, xdi_copy_from_user); - } - if (!file->private_data) { - return (-ENODEV); + if (!file->private_data) + return (-ENODEV); + ret = diva_xdi_write(file->private_data, file, + buf, count, &msg, xdi_copy_from_user); + } else { + ret = diva_xdi_write(file->private_data, file, + buf, count, NULL, xdi_copy_from_user); } - ret = diva_xdi_write(file->private_data, file, - buf, count, xdi_copy_from_user); switch (ret) { case -1: /* Message should be removed from rx mailbox first */ ret = -EBUSY; @@ -622,11 +625,12 @@ static ssize_t divas_write(struct file *file, const char __user *buf, static ssize_t divas_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { + diva_xdi_um_cfg_cmd_t msg; int ret = -EINVAL; if (!file->private_data) { file->private_data = diva_xdi_open_adapter(file, buf, - count, + count, &msg, xdi_copy_from_user); } if (!file->private_data) { diff --git a/drivers/isdn/hysdn/hycapi.c b/drivers/isdn/hysdn/hycapi.c index eac0f51a0f60..a2c15cd7bf67 100644 --- a/drivers/isdn/hysdn/hycapi.c +++ b/drivers/isdn/hysdn/hycapi.c @@ -467,19 +467,6 @@ static int hycapi_proc_show(struct seq_file *m, void *v) return 0; } -static int hycapi_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, hycapi_proc_show, PDE_DATA(inode)); -} - -static const struct file_operations hycapi_proc_fops = { - .owner = THIS_MODULE, - .open = hycapi_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - /************************************************************** hycapi_load_firmware @@ -774,7 +761,7 @@ hycapi_capi_create(hysdn_card *card) ctrl->load_firmware = hycapi_load_firmware; ctrl->reset_ctr = hycapi_reset_ctr; ctrl->procinfo = hycapi_procinfo; - ctrl->proc_fops = &hycapi_proc_fops; + ctrl->proc_show = hycapi_proc_show; strcpy(ctrl->name, cinfo->cardname); ctrl->owner = THIS_MODULE; diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c index 1f8f489b4167..98f90aadd141 100644 --- a/drivers/isdn/mISDN/socket.c +++ b/drivers/isdn/mISDN/socket.c @@ -588,7 +588,7 @@ static const struct proto_ops data_sock_ops = { .getname = data_sock_getname, .sendmsg = mISDN_sock_sendmsg, .recvmsg = mISDN_sock_recvmsg, - .poll = datagram_poll, + .poll_mask = datagram_poll_mask, .listen = sock_no_listen, .shutdown = sock_no_shutdown, .setsockopt = data_sock_setsockopt, @@ -745,7 +745,6 @@ static const struct proto_ops base_sock_ops = { .getname = sock_no_getname, .sendmsg = sock_no_sendmsg, .recvmsg = sock_no_recvmsg, - .poll = sock_no_poll, .listen = sock_no_listen, .shutdown = sock_no_shutdown, .setsockopt = sock_no_setsockopt, diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 2c896c0e69e1..6e3a998f3370 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -104,6 +104,19 @@ config LEDS_CPCAP This option enables support for LEDs offered by Motorola's CPCAP PMIC. +config LEDS_CR0014114 + tristate "LED Support for Crane CR0014114" + depends on LEDS_CLASS + depends on SPI + depends on OF + help + This option enables support for CR0014114 LED Board which + is widely used in vending machines produced by + Crane Merchandising Systems. + + To compile this driver as a module, choose M here: the module + will be called leds-cr0014114. + config LEDS_LM3530 tristate "LCD Backlight driver for LM3530" depends on LEDS_CLASS @@ -145,6 +158,15 @@ config LEDS_LM3692X This option enables support for the TI LM3692x family of white LED string drivers used for backlighting. +config LEDS_LM3601X + tristate "LED support for LM3601x Chips" + depends on LEDS_CLASS && I2C + depends on LEDS_CLASS_FLASH + select REGMAP_I2C + help + This option enables support for the TI LM3601x family + of flash, torch and indicator classes. + config LEDS_LOCOMO tristate "LED Support for Locomo device" depends on LEDS_CLASS @@ -647,6 +669,17 @@ config LEDS_IS31FL32XX LED controllers. They are I2C devices with multiple constant-current channels, each with independent 256-level PWM control. +config LEDS_SC27XX_BLTC + tristate "LED support for the SC27xx breathing light controller" + depends on LEDS_CLASS && MFD_SC27XX_PMIC + depends on OF + help + Say Y here to include support for the SC27xx breathing light controller + LEDs. + + This driver can also be built as a module. If so the module will be + called leds-sc27xx-bltc. + comment "LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM)" config LEDS_BLINKM diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 91eca81cae82..420b5d2cfa62 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -76,8 +76,11 @@ obj-$(CONFIG_LEDS_MLXREG) += leds-mlxreg.o obj-$(CONFIG_LEDS_NIC78BX) += leds-nic78bx.o obj-$(CONFIG_LEDS_MT6323) += leds-mt6323.o obj-$(CONFIG_LEDS_LM3692X) += leds-lm3692x.o +obj-$(CONFIG_LEDS_SC27XX_BLTC) += leds-sc27xx-bltc.o +obj-$(CONFIG_LEDS_LM3601X) += leds-lm3601x.o # LED SPI Drivers +obj-$(CONFIG_LEDS_CR0014114) += leds-cr0014114.o obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o # LED Userspace Drivers diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index b0e2d55acbd6..3c7e3487b373 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -260,10 +260,14 @@ int of_led_classdev_register(struct device *parent, struct device_node *np, if (ret < 0) return ret; + mutex_init(&led_cdev->led_access); + mutex_lock(&led_cdev->led_access); led_cdev->dev = device_create_with_groups(leds_class, parent, 0, led_cdev, led_cdev->groups, "%s", name); - if (IS_ERR(led_cdev->dev)) + if (IS_ERR(led_cdev->dev)) { + mutex_unlock(&led_cdev->led_access); return PTR_ERR(led_cdev->dev); + } led_cdev->dev->of_node = np; if (ret) @@ -274,6 +278,7 @@ int of_led_classdev_register(struct device *parent, struct device_node *np, ret = led_add_brightness_hw_changed(led_cdev); if (ret) { device_unregister(led_cdev->dev); + mutex_unlock(&led_cdev->led_access); return ret; } } @@ -285,7 +290,6 @@ int of_led_classdev_register(struct device *parent, struct device_node *np, #ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED led_cdev->brightness_hw_changed = -1; #endif - mutex_init(&led_cdev->led_access); /* add to the list of leds */ down_write(&leds_list_lock); list_add_tail(&led_cdev->node, &leds_list); @@ -302,6 +306,8 @@ int of_led_classdev_register(struct device *parent, struct device_node *np, led_trigger_set_default(led_cdev); #endif + mutex_unlock(&led_cdev->led_access); + dev_dbg(parent, "Registered led device: %s\n", led_cdev->name); diff --git a/drivers/leds/leds-cr0014114.c b/drivers/leds/leds-cr0014114.c new file mode 100644 index 000000000000..a4b1c1dcce7f --- /dev/null +++ b/drivers/leds/leds-cr0014114.c @@ -0,0 +1,315 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 Crane Merchandising Systems. All rights reserved. +// Copyright (C) 2018 Oleh Kravchenko <oleg@kaa.org.ua> + +#include <linux/delay.h> +#include <linux/leds.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/spi/spi.h> +#include <linux/workqueue.h> +#include <uapi/linux/uleds.h> + +/* + * CR0014114 SPI protocol descrtiption: + * +----+-----------------------------------+----+ + * | CMD| BRIGHTNESS |CRC | + * +----+-----------------------------------+----+ + * | | LED0| LED1| LED2| LED3| LED4| LED5| | + * | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | + * | |R|G|B|R|G|B|R|G|B|R|G|B|R|G|B|R|G|B| | + * | 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1 | + * | |1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1| | + * | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | + * | | 18 | | + * +----+-----------------------------------+----+ + * | 20 | + * +---------------------------------------------+ + * + * PS: Boards can be connected to the chain: + * SPI -> board0 -> board1 -> board2 .. + */ + +/* CR0014114 SPI commands */ +#define CR_SET_BRIGHTNESS 0x80 +#define CR_INIT_REENUMERATE 0x81 +#define CR_NEXT_REENUMERATE 0x82 + +/* CR0014114 default settings */ +#define CR_MAX_BRIGHTNESS GENMASK(6, 0) +#define CR_FW_DELAY_MSEC 10 +#define CR_RECOUNT_DELAY (HZ * 3600) + +struct cr0014114_led { + char name[LED_MAX_NAME_SIZE]; + struct cr0014114 *priv; + struct led_classdev ldev; + u8 brightness; +}; + +struct cr0014114 { + bool do_recount; + size_t count; + struct delayed_work work; + struct device *dev; + struct mutex lock; + struct spi_device *spi; + u8 *buf; + unsigned long delay; + struct cr0014114_led leds[]; +}; + +static void cr0014114_calc_crc(u8 *buf, const size_t len) +{ + size_t i; + u8 crc; + + for (i = 1, crc = 1; i < len - 1; i++) + crc += buf[i]; + crc |= BIT(7); + + /* special case when CRC matches the SPI commands */ + if (crc == CR_SET_BRIGHTNESS || + crc == CR_INIT_REENUMERATE || + crc == CR_NEXT_REENUMERATE) + crc = 0xfe; + + buf[len - 1] = crc; +} + +static int cr0014114_recount(struct cr0014114 *priv) +{ + int ret; + size_t i; + u8 cmd; + + dev_dbg(priv->dev, "LEDs recount is started\n"); + + cmd = CR_INIT_REENUMERATE; + ret = spi_write(priv->spi, &cmd, sizeof(cmd)); + if (ret) + goto err; + + cmd = CR_NEXT_REENUMERATE; + for (i = 0; i < priv->count; i++) { + msleep(CR_FW_DELAY_MSEC); + + ret = spi_write(priv->spi, &cmd, sizeof(cmd)); + if (ret) + goto err; + } + +err: + dev_dbg(priv->dev, "LEDs recount is finished\n"); + + if (ret) + dev_err(priv->dev, "with error %d", ret); + + return ret; +} + +static int cr0014114_sync(struct cr0014114 *priv) +{ + int ret; + size_t i; + unsigned long udelay, now = jiffies; + + /* to avoid SPI mistiming with firmware we should wait some time */ + if (time_after(priv->delay, now)) { + udelay = jiffies_to_usecs(priv->delay - now); + usleep_range(udelay, udelay + 1); + } + + if (unlikely(priv->do_recount)) { + ret = cr0014114_recount(priv); + if (ret) + goto err; + + priv->do_recount = false; + msleep(CR_FW_DELAY_MSEC); + } + + priv->buf[0] = CR_SET_BRIGHTNESS; + for (i = 0; i < priv->count; i++) + priv->buf[i + 1] = priv->leds[i].brightness; + cr0014114_calc_crc(priv->buf, priv->count + 2); + ret = spi_write(priv->spi, priv->buf, priv->count + 2); + +err: + priv->delay = jiffies + msecs_to_jiffies(CR_FW_DELAY_MSEC); + + return ret; +} + +static void cr0014114_recount_work(struct work_struct *work) +{ + int ret; + struct cr0014114 *priv = container_of(work, + struct cr0014114, + work.work); + + mutex_lock(&priv->lock); + priv->do_recount = true; + ret = cr0014114_sync(priv); + mutex_unlock(&priv->lock); + + if (ret) + dev_warn(priv->dev, "sync of LEDs failed %d\n", ret); + + schedule_delayed_work(&priv->work, CR_RECOUNT_DELAY); +} + +static int cr0014114_set_sync(struct led_classdev *ldev, + enum led_brightness brightness) +{ + int ret; + struct cr0014114_led *led = container_of(ldev, + struct cr0014114_led, + ldev); + + dev_dbg(led->priv->dev, "Set brightness of %s to %d\n", + led->name, brightness); + + mutex_lock(&led->priv->lock); + led->brightness = (u8)brightness; + ret = cr0014114_sync(led->priv); + mutex_unlock(&led->priv->lock); + + return ret; +} + +static int cr0014114_probe_dt(struct cr0014114 *priv) +{ + size_t i = 0; + struct cr0014114_led *led; + struct fwnode_handle *child; + struct device_node *np; + int ret; + const char *str; + + device_for_each_child_node(priv->dev, child) { + np = to_of_node(child); + led = &priv->leds[i]; + + ret = fwnode_property_read_string(child, "label", &str); + if (ret) + snprintf(led->name, sizeof(led->name), + "cr0014114::"); + else + snprintf(led->name, sizeof(led->name), + "cr0014114:%s", str); + + fwnode_property_read_string(child, "linux,default-trigger", + &led->ldev.default_trigger); + + led->priv = priv; + led->ldev.name = led->name; + led->ldev.max_brightness = CR_MAX_BRIGHTNESS; + led->ldev.brightness_set_blocking = cr0014114_set_sync; + + ret = devm_of_led_classdev_register(priv->dev, np, + &led->ldev); + if (ret) { + dev_err(priv->dev, + "failed to register LED device %s, err %d", + led->name, ret); + fwnode_handle_put(child); + return ret; + } + + led->ldev.dev->of_node = np; + + i++; + } + + return 0; +} + +static int cr0014114_probe(struct spi_device *spi) +{ + struct cr0014114 *priv; + size_t count; + int ret; + + count = device_get_child_node_count(&spi->dev); + if (!count) { + dev_err(&spi->dev, "LEDs are not defined in device tree!"); + return -ENODEV; + } + + priv = devm_kzalloc(&spi->dev, + sizeof(*priv) + sizeof(*priv->leds) * count, + GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->buf = devm_kzalloc(&spi->dev, count + 2, GFP_KERNEL); + if (!priv->buf) + return -ENOMEM; + + mutex_init(&priv->lock); + INIT_DELAYED_WORK(&priv->work, cr0014114_recount_work); + priv->count = count; + priv->dev = &spi->dev; + priv->spi = spi; + priv->delay = jiffies - + msecs_to_jiffies(CR_FW_DELAY_MSEC); + + priv->do_recount = true; + ret = cr0014114_sync(priv); + if (ret) { + dev_err(priv->dev, "first recount failed %d\n", ret); + return ret; + } + + priv->do_recount = true; + ret = cr0014114_sync(priv); + if (ret) { + dev_err(priv->dev, "second recount failed %d\n", ret); + return ret; + } + + ret = cr0014114_probe_dt(priv); + if (ret) + return ret; + + /* setup recount work to workaround buggy firmware */ + schedule_delayed_work(&priv->work, CR_RECOUNT_DELAY); + + spi_set_drvdata(spi, priv); + + return 0; +} + +static int cr0014114_remove(struct spi_device *spi) +{ + struct cr0014114 *priv = spi_get_drvdata(spi); + + cancel_delayed_work_sync(&priv->work); + mutex_destroy(&priv->lock); + + return 0; +} + +static const struct of_device_id cr0014114_dt_ids[] = { + { .compatible = "crane,cr0014114", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, cr0014114_dt_ids); + +static struct spi_driver cr0014114_driver = { + .probe = cr0014114_probe, + .remove = cr0014114_remove, + .driver = { + .name = KBUILD_MODNAME, + .of_match_table = cr0014114_dt_ids, + }, +}; + +module_spi_driver(cr0014114_driver); + +MODULE_AUTHOR("Oleh Kravchenko <oleg@kaa.org.ua>"); +MODULE_DESCRIPTION("cr0014114 LED driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("spi:cr0014114"); diff --git a/drivers/leds/leds-lm3601x.c b/drivers/leds/leds-lm3601x.c new file mode 100644 index 000000000000..081aa71e43a3 --- /dev/null +++ b/drivers/leds/leds-lm3601x.c @@ -0,0 +1,487 @@ +// SPDX-License-Identifier: GPL-2.0 +// Flash and torch driver for Texas Instruments LM3601X LED +// Flash driver chip family +// Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ + +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/leds.h> +#include <linux/led-class-flash.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/slab.h> +#include <uapi/linux/uleds.h> + +#define LM3601X_LED_IR 0x0 +#define LM3601X_LED_TORCH 0x1 + +/* Registers */ +#define LM3601X_ENABLE_REG 0x01 +#define LM3601X_CFG_REG 0x02 +#define LM3601X_LED_FLASH_REG 0x03 +#define LM3601X_LED_TORCH_REG 0x04 +#define LM3601X_FLAGS_REG 0x05 +#define LM3601X_DEV_ID_REG 0x06 + +#define LM3601X_SW_RESET BIT(7) + +/* Enable Mode bits */ +#define LM3601X_MODE_STANDBY 0x00 +#define LM3601X_MODE_IR_DRV BIT(0) +#define LM3601X_MODE_TORCH BIT(1) +#define LM3601X_MODE_STROBE (BIT(0) | BIT(1)) +#define LM3601X_STRB_EN BIT(2) +#define LM3601X_STRB_EDGE_TRIG BIT(3) +#define LM3601X_IVFM_EN BIT(4) + +#define LM36010_BOOST_LIMIT_28 BIT(5) +#define LM36010_BOOST_FREQ_4MHZ BIT(6) +#define LM36010_BOOST_MODE_PASS BIT(7) + +/* Flag Mask */ +#define LM3601X_FLASH_TIME_OUT BIT(0) +#define LM3601X_UVLO_FAULT BIT(1) +#define LM3601X_THERM_SHUTDOWN BIT(2) +#define LM3601X_THERM_CURR BIT(3) +#define LM36010_CURR_LIMIT BIT(4) +#define LM3601X_SHORT_FAULT BIT(5) +#define LM3601X_IVFM_TRIP BIT(6) +#define LM36010_OVP_FAULT BIT(7) + +#define LM3601X_MAX_TORCH_I_UA 376000 +#define LM3601X_MIN_TORCH_I_UA 2400 +#define LM3601X_TORCH_REG_DIV 2965 + +#define LM3601X_MAX_STROBE_I_UA 1500000 +#define LM3601X_MIN_STROBE_I_UA 11000 +#define LM3601X_STROBE_REG_DIV 11800 + +#define LM3601X_TIMEOUT_MASK 0x1e +#define LM3601X_ENABLE_MASK (LM3601X_MODE_IR_DRV | LM3601X_MODE_TORCH) + +#define LM3601X_LOWER_STEP_US 40000 +#define LM3601X_UPPER_STEP_US 200000 +#define LM3601X_MIN_TIMEOUT_US 40000 +#define LM3601X_MAX_TIMEOUT_US 1600000 +#define LM3601X_TIMEOUT_XOVER_US 400000 + +enum lm3601x_type { + CHIP_LM36010 = 0, + CHIP_LM36011, +}; + +/** + * struct lm3601x_led - + * @fled_cdev: flash LED class device pointer + * @client: Pointer to the I2C client + * @regmap: Devices register map + * @lock: Lock for reading/writing the device + * @led_name: LED label for the Torch or IR LED + * @flash_timeout: the timeout for the flash + * @last_flag: last known flags register value + * @torch_current_max: maximum current for the torch + * @flash_current_max: maximum current for the flash + * @max_flash_timeout: maximum timeout for the flash + * @led_mode: The mode to enable either IR or Torch + */ +struct lm3601x_led { + struct led_classdev_flash fled_cdev; + struct i2c_client *client; + struct regmap *regmap; + struct mutex lock; + + char led_name[LED_MAX_NAME_SIZE]; + + unsigned int flash_timeout; + unsigned int last_flag; + + u32 torch_current_max; + u32 flash_current_max; + u32 max_flash_timeout; + + u32 led_mode; +}; + +static const struct reg_default lm3601x_regmap_defs[] = { + { LM3601X_ENABLE_REG, 0x20 }, + { LM3601X_CFG_REG, 0x15 }, + { LM3601X_LED_FLASH_REG, 0x00 }, + { LM3601X_LED_TORCH_REG, 0x00 }, +}; + +static bool lm3601x_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case LM3601X_FLAGS_REG: + return true; + default: + return false; + } +} + +static const struct regmap_config lm3601x_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = LM3601X_DEV_ID_REG, + .reg_defaults = lm3601x_regmap_defs, + .num_reg_defaults = ARRAY_SIZE(lm3601x_regmap_defs), + .cache_type = REGCACHE_RBTREE, + .volatile_reg = lm3601x_volatile_reg, +}; + +static struct lm3601x_led *fled_cdev_to_led(struct led_classdev_flash *fled_cdev) +{ + return container_of(fled_cdev, struct lm3601x_led, fled_cdev); +} + +static int lm3601x_read_faults(struct lm3601x_led *led) +{ + int flags_val; + int ret; + + ret = regmap_read(led->regmap, LM3601X_FLAGS_REG, &flags_val); + if (ret < 0) + return -EIO; + + led->last_flag = 0; + + if (flags_val & LM36010_OVP_FAULT) + led->last_flag |= LED_FAULT_OVER_VOLTAGE; + + if (flags_val & (LM3601X_THERM_SHUTDOWN | LM3601X_THERM_CURR)) + led->last_flag |= LED_FAULT_OVER_TEMPERATURE; + + if (flags_val & LM3601X_SHORT_FAULT) + led->last_flag |= LED_FAULT_SHORT_CIRCUIT; + + if (flags_val & LM36010_CURR_LIMIT) + led->last_flag |= LED_FAULT_OVER_CURRENT; + + if (flags_val & LM3601X_UVLO_FAULT) + led->last_flag |= LED_FAULT_UNDER_VOLTAGE; + + if (flags_val & LM3601X_IVFM_TRIP) + led->last_flag |= LED_FAULT_INPUT_VOLTAGE; + + if (flags_val & LM3601X_THERM_SHUTDOWN) + led->last_flag |= LED_FAULT_LED_OVER_TEMPERATURE; + + return led->last_flag; +} + +static int lm3601x_brightness_set(struct led_classdev *cdev, + enum led_brightness brightness) +{ + struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(cdev); + struct lm3601x_led *led = fled_cdev_to_led(fled_cdev); + int ret, led_mode_val; + + mutex_lock(&led->lock); + + ret = lm3601x_read_faults(led); + if (ret < 0) + goto out; + + if (led->led_mode == LM3601X_LED_TORCH) + led_mode_val = LM3601X_MODE_TORCH; + else + led_mode_val = LM3601X_MODE_IR_DRV; + + if (brightness == LED_OFF) { + ret = regmap_update_bits(led->regmap, LM3601X_ENABLE_REG, + led_mode_val, LED_OFF); + goto out; + } + + ret = regmap_write(led->regmap, LM3601X_LED_TORCH_REG, brightness); + if (ret < 0) + goto out; + + ret = regmap_update_bits(led->regmap, LM3601X_ENABLE_REG, + LM3601X_MODE_TORCH | LM3601X_MODE_IR_DRV, + led_mode_val); +out: + mutex_unlock(&led->lock); + return ret; +} + +static int lm3601x_strobe_set(struct led_classdev_flash *fled_cdev, + bool state) +{ + struct lm3601x_led *led = fled_cdev_to_led(fled_cdev); + int timeout_reg_val; + int current_timeout; + int ret; + + mutex_lock(&led->lock); + + ret = regmap_read(led->regmap, LM3601X_CFG_REG, ¤t_timeout); + if (ret < 0) + goto out; + + if (led->flash_timeout >= LM3601X_TIMEOUT_XOVER_US) + timeout_reg_val = led->flash_timeout / LM3601X_UPPER_STEP_US + 0x07; + else + timeout_reg_val = led->flash_timeout / LM3601X_LOWER_STEP_US - 0x01; + + if (led->flash_timeout != current_timeout) + ret = regmap_update_bits(led->regmap, LM3601X_CFG_REG, + LM3601X_TIMEOUT_MASK, timeout_reg_val); + + if (state) + ret = regmap_update_bits(led->regmap, LM3601X_ENABLE_REG, + LM3601X_MODE_TORCH | LM3601X_MODE_IR_DRV, + LM3601X_MODE_STROBE); + else + ret = regmap_update_bits(led->regmap, LM3601X_ENABLE_REG, + LM3601X_MODE_STROBE, LED_OFF); + + ret = lm3601x_read_faults(led); +out: + mutex_unlock(&led->lock); + return ret; +} + +static int lm3601x_flash_brightness_set(struct led_classdev_flash *fled_cdev, + u32 brightness) +{ + struct lm3601x_led *led = fled_cdev_to_led(fled_cdev); + u8 brightness_val; + int ret; + + mutex_lock(&led->lock); + ret = lm3601x_read_faults(led); + if (ret < 0) + goto out; + + if (brightness == LED_OFF) { + ret = regmap_update_bits(led->regmap, LM3601X_ENABLE_REG, + LM3601X_MODE_STROBE, LED_OFF); + goto out; + } + + brightness_val = brightness / LM3601X_STROBE_REG_DIV; + + ret = regmap_write(led->regmap, LM3601X_LED_FLASH_REG, brightness_val); +out: + mutex_unlock(&led->lock); + return ret; +} + +static int lm3601x_flash_timeout_set(struct led_classdev_flash *fled_cdev, + u32 timeout) +{ + struct lm3601x_led *led = fled_cdev_to_led(fled_cdev); + + mutex_lock(&led->lock); + + led->flash_timeout = timeout; + + mutex_unlock(&led->lock); + + return 0; +} + +static int lm3601x_strobe_get(struct led_classdev_flash *fled_cdev, bool *state) +{ + struct lm3601x_led *led = fled_cdev_to_led(fled_cdev); + int strobe_state; + int ret; + + mutex_lock(&led->lock); + + ret = regmap_read(led->regmap, LM3601X_ENABLE_REG, &strobe_state); + if (ret < 0) + goto out; + + *state = strobe_state & LM3601X_MODE_STROBE; + +out: + mutex_unlock(&led->lock); + return ret; +} + +static int lm3601x_flash_fault_get(struct led_classdev_flash *fled_cdev, + u32 *fault) +{ + struct lm3601x_led *led = fled_cdev_to_led(fled_cdev); + + lm3601x_read_faults(led); + + *fault = led->last_flag; + + return 0; +} + +static const struct led_flash_ops flash_ops = { + .flash_brightness_set = lm3601x_flash_brightness_set, + .strobe_set = lm3601x_strobe_set, + .strobe_get = lm3601x_strobe_get, + .timeout_set = lm3601x_flash_timeout_set, + .fault_get = lm3601x_flash_fault_get, +}; + +static int lm3601x_register_leds(struct lm3601x_led *led) +{ + struct led_classdev *led_cdev; + struct led_flash_setting *setting; + + led->fled_cdev.ops = &flash_ops; + + setting = &led->fled_cdev.timeout; + setting->min = LM3601X_MIN_TIMEOUT_US; + setting->max = led->max_flash_timeout; + setting->step = LM3601X_LOWER_STEP_US; + setting->val = led->max_flash_timeout; + + setting = &led->fled_cdev.brightness; + setting->min = LM3601X_MIN_STROBE_I_UA; + setting->max = led->flash_current_max; + setting->step = LM3601X_TORCH_REG_DIV; + setting->val = led->flash_current_max; + + led_cdev = &led->fled_cdev.led_cdev; + led_cdev->name = led->led_name; + led_cdev->brightness_set_blocking = lm3601x_brightness_set; + led_cdev->max_brightness = DIV_ROUND_UP(led->torch_current_max, + LM3601X_TORCH_REG_DIV); + led_cdev->flags |= LED_DEV_CAP_FLASH; + + return led_classdev_flash_register(&led->client->dev, &led->fled_cdev); +} + +static int lm3601x_parse_node(struct lm3601x_led *led) +{ + struct fwnode_handle *child = NULL; + int ret = -ENODEV; + const char *name; + + child = device_get_next_child_node(&led->client->dev, child); + if (!child) { + dev_err(&led->client->dev, "No LED Child node\n"); + return ret; + } + + ret = fwnode_property_read_u32(child, "reg", &led->led_mode); + if (ret) { + dev_err(&led->client->dev, "reg DT property missing\n"); + goto out_err; + } + + if (led->led_mode > LM3601X_LED_TORCH || + led->led_mode < LM3601X_LED_IR) { + dev_warn(&led->client->dev, "Invalid led mode requested\n"); + ret = -EINVAL; + goto out_err; + } + + ret = fwnode_property_read_string(child, "label", &name); + if (ret) { + if (led->led_mode == LM3601X_LED_TORCH) + name = "torch"; + else + name = "infrared"; + } + + snprintf(led->led_name, sizeof(led->led_name), + "%s:%s", led->client->name, name); + + ret = fwnode_property_read_u32(child, "led-max-microamp", + &led->torch_current_max); + if (ret) { + dev_warn(&led->client->dev, + "led-max-microamp DT property missing\n"); + goto out_err; + } + + ret = fwnode_property_read_u32(child, "flash-max-microamp", + &led->flash_current_max); + if (ret) { + dev_warn(&led->client->dev, + "flash-max-microamp DT property missing\n"); + goto out_err; + } + + ret = fwnode_property_read_u32(child, "flash-max-timeout-us", + &led->max_flash_timeout); + if (ret) { + dev_warn(&led->client->dev, + "flash-max-timeout-us DT property missing\n"); + goto out_err; + } + +out_err: + fwnode_handle_put(child); + return ret; +} + +static int lm3601x_probe(struct i2c_client *client) +{ + struct lm3601x_led *led; + int ret; + + led = devm_kzalloc(&client->dev, sizeof(*led), GFP_KERNEL); + if (!led) + return -ENOMEM; + + led->client = client; + i2c_set_clientdata(client, led); + + ret = lm3601x_parse_node(led); + if (ret) + return -ENODEV; + + led->regmap = devm_regmap_init_i2c(client, &lm3601x_regmap); + if (IS_ERR(led->regmap)) { + ret = PTR_ERR(led->regmap); + dev_err(&client->dev, + "Failed to allocate register map: %d\n", ret); + return ret; + } + + mutex_init(&led->lock); + + return lm3601x_register_leds(led); +} + +static int lm3601x_remove(struct i2c_client *client) +{ + struct lm3601x_led *led = i2c_get_clientdata(client); + + led_classdev_flash_unregister(&led->fled_cdev); + mutex_destroy(&led->lock); + + return regmap_update_bits(led->regmap, LM3601X_ENABLE_REG, + LM3601X_ENABLE_MASK, + LM3601X_MODE_STANDBY); +} + +static const struct i2c_device_id lm3601x_id[] = { + { "LM36010", CHIP_LM36010 }, + { "LM36011", CHIP_LM36011 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, lm3601x_id); + +static const struct of_device_id of_lm3601x_leds_match[] = { + { .compatible = "ti,lm36010", }, + { .compatible = "ti,lm36011", }, + { } +}; +MODULE_DEVICE_TABLE(of, of_lm3601x_leds_match); + +static struct i2c_driver lm3601x_i2c_driver = { + .driver = { + .name = "lm3601x", + .of_match_table = of_lm3601x_leds_match, + }, + .probe_new = lm3601x_probe, + .remove = lm3601x_remove, + .id_table = lm3601x_id, +}; +module_i2c_driver(lm3601x_i2c_driver); + +MODULE_DESCRIPTION("Texas Instruments Flash Lighting driver for LM3601X"); +MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/leds/leds-sc27xx-bltc.c b/drivers/leds/leds-sc27xx-bltc.c new file mode 100644 index 000000000000..9d9b7aab843f --- /dev/null +++ b/drivers/leds/leds-sc27xx-bltc.c @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2018 Spreadtrum Communications Inc. + +#include <linux/leds.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <uapi/linux/uleds.h> + +/* PMIC global control register definition */ +#define SC27XX_MODULE_EN0 0xc08 +#define SC27XX_CLK_EN0 0xc18 +#define SC27XX_RGB_CTRL 0xebc + +#define SC27XX_BLTC_EN BIT(9) +#define SC27XX_RTC_EN BIT(7) +#define SC27XX_RGB_PD BIT(0) + +/* Breathing light controller register definition */ +#define SC27XX_LEDS_CTRL 0x00 +#define SC27XX_LEDS_PRESCALE 0x04 +#define SC27XX_LEDS_DUTY 0x08 +#define SC27XX_LEDS_CURVE0 0x0c +#define SC27XX_LEDS_CURVE1 0x10 + +#define SC27XX_CTRL_SHIFT 4 +#define SC27XX_LED_RUN BIT(0) +#define SC27XX_LED_TYPE BIT(1) + +#define SC27XX_DUTY_SHIFT 8 +#define SC27XX_DUTY_MASK GENMASK(15, 0) +#define SC27XX_MOD_MASK GENMASK(7, 0) + +#define SC27XX_LEDS_OFFSET 0x10 +#define SC27XX_LEDS_MAX 3 + +struct sc27xx_led { + char name[LED_MAX_NAME_SIZE]; + struct led_classdev ldev; + struct sc27xx_led_priv *priv; + u8 line; + bool active; +}; + +struct sc27xx_led_priv { + struct sc27xx_led leds[SC27XX_LEDS_MAX]; + struct regmap *regmap; + struct mutex lock; + u32 base; +}; + +#define to_sc27xx_led(ldev) \ + container_of(ldev, struct sc27xx_led, ldev) + +static int sc27xx_led_init(struct regmap *regmap) +{ + int err; + + err = regmap_update_bits(regmap, SC27XX_MODULE_EN0, SC27XX_BLTC_EN, + SC27XX_BLTC_EN); + if (err) + return err; + + err = regmap_update_bits(regmap, SC27XX_CLK_EN0, SC27XX_RTC_EN, + SC27XX_RTC_EN); + if (err) + return err; + + return regmap_update_bits(regmap, SC27XX_RGB_CTRL, SC27XX_RGB_PD, 0); +} + +static u32 sc27xx_led_get_offset(struct sc27xx_led *leds) +{ + return leds->priv->base + SC27XX_LEDS_OFFSET * leds->line; +} + +static int sc27xx_led_enable(struct sc27xx_led *leds, enum led_brightness value) +{ + u32 base = sc27xx_led_get_offset(leds); + u32 ctrl_base = leds->priv->base + SC27XX_LEDS_CTRL; + u8 ctrl_shift = SC27XX_CTRL_SHIFT * leds->line; + struct regmap *regmap = leds->priv->regmap; + int err; + + err = regmap_update_bits(regmap, base + SC27XX_LEDS_DUTY, + SC27XX_DUTY_MASK, + (value << SC27XX_DUTY_SHIFT) | + SC27XX_MOD_MASK); + if (err) + return err; + + return regmap_update_bits(regmap, ctrl_base, + (SC27XX_LED_RUN | SC27XX_LED_TYPE) << ctrl_shift, + (SC27XX_LED_RUN | SC27XX_LED_TYPE) << ctrl_shift); +} + +static int sc27xx_led_disable(struct sc27xx_led *leds) +{ + struct regmap *regmap = leds->priv->regmap; + u32 ctrl_base = leds->priv->base + SC27XX_LEDS_CTRL; + u8 ctrl_shift = SC27XX_CTRL_SHIFT * leds->line; + + return regmap_update_bits(regmap, ctrl_base, + (SC27XX_LED_RUN | SC27XX_LED_TYPE) << ctrl_shift, 0); +} + +static int sc27xx_led_set(struct led_classdev *ldev, enum led_brightness value) +{ + struct sc27xx_led *leds = to_sc27xx_led(ldev); + int err; + + mutex_lock(&leds->priv->lock); + + if (value == LED_OFF) + err = sc27xx_led_disable(leds); + else + err = sc27xx_led_enable(leds, value); + + mutex_unlock(&leds->priv->lock); + + return err; +} + +static int sc27xx_led_register(struct device *dev, struct sc27xx_led_priv *priv) +{ + int i, err; + + err = sc27xx_led_init(priv->regmap); + if (err) + return err; + + for (i = 0; i < SC27XX_LEDS_MAX; i++) { + struct sc27xx_led *led = &priv->leds[i]; + + if (!led->active) + continue; + + led->line = i; + led->priv = priv; + led->ldev.name = led->name; + led->ldev.brightness_set_blocking = sc27xx_led_set; + + err = devm_led_classdev_register(dev, &led->ldev); + if (err) + return err; + } + + return 0; +} + +static int sc27xx_led_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node, *child; + struct sc27xx_led_priv *priv; + const char *str; + u32 base, count, reg; + int err; + + count = of_get_child_count(np); + if (!count || count > SC27XX_LEDS_MAX) + return -EINVAL; + + err = of_property_read_u32(np, "reg", &base); + if (err) { + dev_err(dev, "fail to get reg of property\n"); + return err; + } + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + platform_set_drvdata(pdev, priv); + mutex_init(&priv->lock); + priv->base = base; + priv->regmap = dev_get_regmap(dev->parent, NULL); + if (!priv->regmap) { + err = -ENODEV; + dev_err(dev, "failed to get regmap: %d\n", err); + return err; + } + + for_each_child_of_node(np, child) { + err = of_property_read_u32(child, "reg", ®); + if (err) { + of_node_put(child); + mutex_destroy(&priv->lock); + return err; + } + + if (reg >= SC27XX_LEDS_MAX || priv->leds[reg].active) { + of_node_put(child); + mutex_destroy(&priv->lock); + return -EINVAL; + } + + priv->leds[reg].active = true; + + err = of_property_read_string(child, "label", &str); + if (err) + snprintf(priv->leds[reg].name, LED_MAX_NAME_SIZE, + "sc27xx::"); + else + snprintf(priv->leds[reg].name, LED_MAX_NAME_SIZE, + "sc27xx:%s", str); + } + + err = sc27xx_led_register(dev, priv); + if (err) + mutex_destroy(&priv->lock); + + return err; +} + +static int sc27xx_led_remove(struct platform_device *pdev) +{ + struct sc27xx_led_priv *priv = platform_get_drvdata(pdev); + + mutex_destroy(&priv->lock); + return 0; +} + +static const struct of_device_id sc27xx_led_of_match[] = { + { .compatible = "sprd,sc2731-bltc", }, + { } +}; +MODULE_DEVICE_TABLE(of, sc27xx_led_of_match); + +static struct platform_driver sc27xx_led_driver = { + .driver = { + .name = "sprd-bltc", + .of_match_table = sc27xx_led_of_match, + }, + .probe = sc27xx_led_probe, + .remove = sc27xx_led_remove, +}; + +module_platform_driver(sc27xx_led_driver); + +MODULE_DESCRIPTION("Spreadtrum SC27xx breathing light controller driver"); +MODULE_AUTHOR("Xiaotong Lu <xiaotong.lu@spreadtrum.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/leds/leds-wm831x-status.c b/drivers/leds/leds-wm831x-status.c index be93b20e792a..c5798b92e4d3 100644 --- a/drivers/leds/leds-wm831x-status.c +++ b/drivers/leds/leds-wm831x-status.c @@ -188,24 +188,14 @@ static ssize_t wm831x_status_src_store(struct device *dev, { struct led_classdev *led_cdev = dev_get_drvdata(dev); struct wm831x_status *led = to_wm831x_status(led_cdev); - char name[20]; int i; - size_t len; - name[sizeof(name) - 1] = '\0'; - strncpy(name, buf, sizeof(name) - 1); - len = strlen(name); - - if (len && name[len - 1] == '\n') - name[len - 1] = '\0'; - - for (i = 0; i < ARRAY_SIZE(led_src_texts); i++) { - if (!strcmp(name, led_src_texts[i])) { - mutex_lock(&led->mutex); - led->src = i; - mutex_unlock(&led->mutex); - wm831x_status_set(led); - } + i = sysfs_match_string(led_src_texts, buf); + if (i >= 0) { + mutex_lock(&led->mutex); + led->src = i; + mutex_unlock(&led->mutex); + wm831x_status_set(led); } return size; diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c index 63171cdce270..60aa7bc5a630 100644 --- a/drivers/lightnvm/core.c +++ b/drivers/lightnvm/core.c @@ -431,7 +431,7 @@ static int nvm_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create) return 0; err_sysfs: if (tt->exit) - tt->exit(targetdata); + tt->exit(targetdata, true); err_init: blk_cleanup_queue(tqueue); tdisk->queue = NULL; @@ -446,7 +446,7 @@ err_reserve: return ret; } -static void __nvm_remove_target(struct nvm_target *t) +static void __nvm_remove_target(struct nvm_target *t, bool graceful) { struct nvm_tgt_type *tt = t->type; struct gendisk *tdisk = t->disk; @@ -459,7 +459,7 @@ static void __nvm_remove_target(struct nvm_target *t) tt->sysfs_exit(tdisk); if (tt->exit) - tt->exit(tdisk->private_data); + tt->exit(tdisk->private_data, graceful); nvm_remove_tgt_dev(t->dev, 1); put_disk(tdisk); @@ -489,7 +489,7 @@ static int nvm_remove_tgt(struct nvm_dev *dev, struct nvm_ioctl_remove *remove) mutex_unlock(&dev->mlock); return 1; } - __nvm_remove_target(t); + __nvm_remove_target(t, true); mutex_unlock(&dev->mlock); return 0; @@ -963,7 +963,7 @@ void nvm_unregister(struct nvm_dev *dev) list_for_each_entry_safe(t, tmp, &dev->targets, list) { if (t->dev->parent != dev) continue; - __nvm_remove_target(t); + __nvm_remove_target(t, false); } mutex_unlock(&dev->mlock); diff --git a/drivers/lightnvm/pblk-cache.c b/drivers/lightnvm/pblk-cache.c index 29a23111b31c..b1c6d7eb6115 100644 --- a/drivers/lightnvm/pblk-cache.c +++ b/drivers/lightnvm/pblk-cache.c @@ -44,13 +44,15 @@ retry: goto out; } - if (unlikely(!bio_has_data(bio))) - goto out; - pblk_ppa_set_empty(&w_ctx.ppa); w_ctx.flags = flags; - if (bio->bi_opf & REQ_PREFLUSH) + if (bio->bi_opf & REQ_PREFLUSH) { w_ctx.flags |= PBLK_FLUSH_ENTRY; + pblk_write_kick(pblk); + } + + if (unlikely(!bio_has_data(bio))) + goto out; for (i = 0; i < nr_entries; i++) { void *data = bio_data(bio); diff --git a/drivers/lightnvm/pblk-core.c b/drivers/lightnvm/pblk-core.c index 94d5d97c9d8a..ed9cc977c8b3 100644 --- a/drivers/lightnvm/pblk-core.c +++ b/drivers/lightnvm/pblk-core.c @@ -40,7 +40,7 @@ static void pblk_line_mark_bb(struct work_struct *work) } kfree(ppa); - mempool_free(line_ws, pblk->gen_ws_pool); + mempool_free(line_ws, &pblk->gen_ws_pool); } static void pblk_mark_bb(struct pblk *pblk, struct pblk_line *line, @@ -102,7 +102,7 @@ static void pblk_end_io_erase(struct nvm_rq *rqd) struct pblk *pblk = rqd->private; __pblk_end_io_erase(pblk, rqd); - mempool_free(rqd, pblk->e_rq_pool); + mempool_free(rqd, &pblk->e_rq_pool); } /* @@ -237,15 +237,15 @@ struct nvm_rq *pblk_alloc_rqd(struct pblk *pblk, int type) switch (type) { case PBLK_WRITE: case PBLK_WRITE_INT: - pool = pblk->w_rq_pool; + pool = &pblk->w_rq_pool; rq_size = pblk_w_rq_size; break; case PBLK_READ: - pool = pblk->r_rq_pool; + pool = &pblk->r_rq_pool; rq_size = pblk_g_rq_size; break; default: - pool = pblk->e_rq_pool; + pool = &pblk->e_rq_pool; rq_size = pblk_g_rq_size; } @@ -265,20 +265,22 @@ void pblk_free_rqd(struct pblk *pblk, struct nvm_rq *rqd, int type) case PBLK_WRITE: kfree(((struct pblk_c_ctx *)nvm_rq_to_pdu(rqd))->lun_bitmap); case PBLK_WRITE_INT: - pool = pblk->w_rq_pool; + pool = &pblk->w_rq_pool; break; case PBLK_READ: - pool = pblk->r_rq_pool; + pool = &pblk->r_rq_pool; break; case PBLK_ERASE: - pool = pblk->e_rq_pool; + pool = &pblk->e_rq_pool; break; default: pr_err("pblk: trying to free unknown rqd type\n"); return; } - nvm_dev_dma_free(dev->parent, rqd->meta_list, rqd->dma_meta_list); + if (rqd->meta_list) + nvm_dev_dma_free(dev->parent, rqd->meta_list, + rqd->dma_meta_list); mempool_free(rqd, pool); } @@ -292,7 +294,7 @@ void pblk_bio_free_pages(struct pblk *pblk, struct bio *bio, int off, for (i = off; i < nr_pages + off; i++) { bv = bio->bi_io_vec[i]; - mempool_free(bv.bv_page, pblk->page_bio_pool); + mempool_free(bv.bv_page, &pblk->page_bio_pool); } } @@ -304,23 +306,23 @@ int pblk_bio_add_pages(struct pblk *pblk, struct bio *bio, gfp_t flags, int i, ret; for (i = 0; i < nr_pages; i++) { - page = mempool_alloc(pblk->page_bio_pool, flags); + page = mempool_alloc(&pblk->page_bio_pool, flags); ret = bio_add_pc_page(q, bio, page, PBLK_EXPOSED_PAGE_SIZE, 0); if (ret != PBLK_EXPOSED_PAGE_SIZE) { pr_err("pblk: could not add page to bio\n"); - mempool_free(page, pblk->page_bio_pool); + mempool_free(page, &pblk->page_bio_pool); goto err; } } return 0; err: - pblk_bio_free_pages(pblk, bio, 0, i - 1); + pblk_bio_free_pages(pblk, bio, (bio->bi_vcnt - i), i); return -1; } -static void pblk_write_kick(struct pblk *pblk) +void pblk_write_kick(struct pblk *pblk) { wake_up_process(pblk->writer_ts); mod_timer(&pblk->wtimer, jiffies + msecs_to_jiffies(1000)); @@ -342,13 +344,6 @@ void pblk_write_should_kick(struct pblk *pblk) pblk_write_kick(pblk); } -void pblk_end_io_sync(struct nvm_rq *rqd) -{ - struct completion *waiting = rqd->private; - - complete(waiting); -} - static void pblk_wait_for_meta(struct pblk *pblk) { do { @@ -380,7 +375,13 @@ struct list_head *pblk_line_gc_list(struct pblk *pblk, struct pblk_line *line) lockdep_assert_held(&line->lock); - if (!vsc) { + if (line->w_err_gc->has_write_err) { + if (line->gc_group != PBLK_LINEGC_WERR) { + line->gc_group = PBLK_LINEGC_WERR; + move_list = &l_mg->gc_werr_list; + pblk_rl_werr_line_in(&pblk->rl); + } + } else if (!vsc) { if (line->gc_group != PBLK_LINEGC_FULL) { line->gc_group = PBLK_LINEGC_FULL; move_list = &l_mg->gc_full_list; @@ -467,16 +468,13 @@ int pblk_submit_io(struct pblk *pblk, struct nvm_rq *rqd) { struct nvm_tgt_dev *dev = pblk->dev; -#ifdef CONFIG_NVM_DEBUG - int ret; + atomic_inc(&pblk->inflight_io); - ret = pblk_check_io(pblk, rqd); - if (ret) - return ret; +#ifdef CONFIG_NVM_DEBUG + if (pblk_check_io(pblk, rqd)) + return NVM_IO_ERR; #endif - atomic_inc(&pblk->inflight_io); - return nvm_submit_io(dev, rqd); } @@ -484,16 +482,13 @@ int pblk_submit_io_sync(struct pblk *pblk, struct nvm_rq *rqd) { struct nvm_tgt_dev *dev = pblk->dev; -#ifdef CONFIG_NVM_DEBUG - int ret; + atomic_inc(&pblk->inflight_io); - ret = pblk_check_io(pblk, rqd); - if (ret) - return ret; +#ifdef CONFIG_NVM_DEBUG + if (pblk_check_io(pblk, rqd)) + return NVM_IO_ERR; #endif - atomic_inc(&pblk->inflight_io); - return nvm_submit_io_sync(dev, rqd); } @@ -856,9 +851,10 @@ static int pblk_line_submit_smeta_io(struct pblk *pblk, struct pblk_line *line, atomic_dec(&pblk->inflight_io); if (rqd.error) { - if (dir == PBLK_WRITE) + if (dir == PBLK_WRITE) { pblk_log_write_err(pblk, &rqd); - else if (dir == PBLK_READ) + ret = 1; + } else if (dir == PBLK_READ) pblk_log_read_err(pblk, &rqd); } @@ -1071,6 +1067,25 @@ static int pblk_line_init_metadata(struct pblk *pblk, struct pblk_line *line, return 1; } +static int pblk_line_alloc_bitmaps(struct pblk *pblk, struct pblk_line *line) +{ + struct pblk_line_meta *lm = &pblk->lm; + + line->map_bitmap = kzalloc(lm->sec_bitmap_len, GFP_KERNEL); + if (!line->map_bitmap) + return -ENOMEM; + + /* will be initialized using bb info from map_bitmap */ + line->invalid_bitmap = kmalloc(lm->sec_bitmap_len, GFP_KERNEL); + if (!line->invalid_bitmap) { + kfree(line->map_bitmap); + line->map_bitmap = NULL; + return -ENOMEM; + } + + return 0; +} + /* For now lines are always assumed full lines. Thus, smeta former and current * lun bitmaps are omitted. */ @@ -1108,7 +1123,7 @@ static int pblk_line_init_bb(struct pblk *pblk, struct pblk_line *line, if (init && pblk_line_submit_smeta_io(pblk, line, off, PBLK_WRITE)) { pr_debug("pblk: line smeta I/O failed. Retry\n"); - return 1; + return 0; } bitmap_copy(line->invalid_bitmap, line->map_bitmap, lm->sec_per_line); @@ -1174,19 +1189,9 @@ static int pblk_prepare_new_line(struct pblk *pblk, struct pblk_line *line) static int pblk_line_prepare(struct pblk *pblk, struct pblk_line *line) { struct pblk_line_meta *lm = &pblk->lm; + int blk_in_line = atomic_read(&line->blk_in_line); int blk_to_erase; - line->map_bitmap = kzalloc(lm->sec_bitmap_len, GFP_ATOMIC); - if (!line->map_bitmap) - return -ENOMEM; - - /* will be initialized using bb info from map_bitmap */ - line->invalid_bitmap = kmalloc(lm->sec_bitmap_len, GFP_ATOMIC); - if (!line->invalid_bitmap) { - kfree(line->map_bitmap); - return -ENOMEM; - } - /* Bad blocks do not need to be erased */ bitmap_copy(line->erase_bitmap, line->blk_bitmap, lm->blk_per_line); @@ -1199,16 +1204,19 @@ static int pblk_line_prepare(struct pblk *pblk, struct pblk_line *line) blk_to_erase = pblk_prepare_new_line(pblk, line); line->state = PBLK_LINESTATE_FREE; } else { - blk_to_erase = atomic_read(&line->blk_in_line); + blk_to_erase = blk_in_line; } - if (line->state != PBLK_LINESTATE_FREE) { - kfree(line->map_bitmap); - kfree(line->invalid_bitmap); + if (blk_in_line < lm->min_blk_line) { spin_unlock(&line->lock); + return -EAGAIN; + } + + if (line->state != PBLK_LINESTATE_FREE) { WARN(1, "pblk: corrupted line %d, state %d\n", line->id, line->state); - return -EAGAIN; + spin_unlock(&line->lock); + return -EINTR; } line->state = PBLK_LINESTATE_OPEN; @@ -1241,13 +1249,16 @@ int pblk_line_recov_alloc(struct pblk *pblk, struct pblk_line *line) } spin_unlock(&l_mg->free_lock); - pblk_rl_free_lines_dec(&pblk->rl, line, true); + ret = pblk_line_alloc_bitmaps(pblk, line); + if (ret) + return ret; if (!pblk_line_init_bb(pblk, line, 0)) { list_add(&line->list, &l_mg->free_list); return -EINTR; } + pblk_rl_free_lines_dec(&pblk->rl, line, true); return 0; } @@ -1259,6 +1270,24 @@ void pblk_line_recov_close(struct pblk *pblk, struct pblk_line *line) line->emeta = NULL; } +static void pblk_line_reinit(struct pblk_line *line) +{ + *line->vsc = cpu_to_le32(EMPTY_ENTRY); + + line->map_bitmap = NULL; + line->invalid_bitmap = NULL; + line->smeta = NULL; + line->emeta = NULL; +} + +void pblk_line_free(struct pblk_line *line) +{ + kfree(line->map_bitmap); + kfree(line->invalid_bitmap); + + pblk_line_reinit(line); +} + struct pblk_line *pblk_line_get(struct pblk *pblk) { struct pblk_line_mgmt *l_mg = &pblk->l_mg; @@ -1292,10 +1321,14 @@ retry: ret = pblk_line_prepare(pblk, line); if (ret) { - if (ret == -EAGAIN) { + switch (ret) { + case -EAGAIN: + list_add(&line->list, &l_mg->bad_list); + goto retry; + case -EINTR: list_add(&line->list, &l_mg->corrupt_list); goto retry; - } else { + default: pr_err("pblk: failed to prepare line %d\n", line->id); list_add(&line->list, &l_mg->free_list); l_mg->nr_free_lines++; @@ -1321,11 +1354,14 @@ retry: return NULL; } + retry_line->map_bitmap = line->map_bitmap; + retry_line->invalid_bitmap = line->invalid_bitmap; retry_line->smeta = line->smeta; retry_line->emeta = line->emeta; retry_line->meta_line = line->meta_line; - pblk_line_free(pblk, line); + pblk_line_reinit(line); + l_mg->data_line = retry_line; spin_unlock(&l_mg->free_lock); @@ -1378,6 +1414,9 @@ struct pblk_line *pblk_line_get_first_data(struct pblk *pblk) } spin_unlock(&l_mg->free_lock); + if (pblk_line_alloc_bitmaps(pblk, line)) + return NULL; + if (pblk_line_erase(pblk, line)) { line = pblk_line_retry(pblk, line); if (!line) @@ -1449,7 +1488,7 @@ static void pblk_line_close_meta_sync(struct pblk *pblk) flush_workqueue(pblk->close_wq); } -void pblk_pipeline_stop(struct pblk *pblk) +void __pblk_pipeline_flush(struct pblk *pblk) { struct pblk_line_mgmt *l_mg = &pblk->l_mg; int ret; @@ -1474,6 +1513,11 @@ void pblk_pipeline_stop(struct pblk *pblk) flush_workqueue(pblk->bb_wq); pblk_line_close_meta_sync(pblk); +} + +void __pblk_pipeline_stop(struct pblk *pblk) +{ + struct pblk_line_mgmt *l_mg = &pblk->l_mg; spin_lock(&l_mg->free_lock); pblk->state = PBLK_STATE_STOPPED; @@ -1482,6 +1526,12 @@ void pblk_pipeline_stop(struct pblk *pblk) spin_unlock(&l_mg->free_lock); } +void pblk_pipeline_stop(struct pblk *pblk) +{ + __pblk_pipeline_flush(pblk); + __pblk_pipeline_stop(pblk); +} + struct pblk_line *pblk_line_replace_data(struct pblk *pblk) { struct pblk_line_mgmt *l_mg = &pblk->l_mg; @@ -1511,6 +1561,9 @@ retry_erase: goto retry_erase; } + if (pblk_line_alloc_bitmaps(pblk, new)) + return NULL; + retry_setup: if (!pblk_line_init_metadata(pblk, new, cur)) { new = pblk_line_retry(pblk, new); @@ -1550,19 +1603,6 @@ out: return new; } -void pblk_line_free(struct pblk *pblk, struct pblk_line *line) -{ - kfree(line->map_bitmap); - kfree(line->invalid_bitmap); - - *line->vsc = cpu_to_le32(EMPTY_ENTRY); - - line->map_bitmap = NULL; - line->invalid_bitmap = NULL; - line->smeta = NULL; - line->emeta = NULL; -} - static void __pblk_line_put(struct pblk *pblk, struct pblk_line *line) { struct pblk_line_mgmt *l_mg = &pblk->l_mg; @@ -1572,9 +1612,14 @@ static void __pblk_line_put(struct pblk *pblk, struct pblk_line *line) WARN_ON(line->state != PBLK_LINESTATE_GC); line->state = PBLK_LINESTATE_FREE; line->gc_group = PBLK_LINEGC_NONE; - pblk_line_free(pblk, line); - spin_unlock(&line->lock); + pblk_line_free(line); + + if (line->w_err_gc->has_write_err) { + pblk_rl_werr_line_out(&pblk->rl); + line->w_err_gc->has_write_err = 0; + } + spin_unlock(&line->lock); atomic_dec(&gc->pipeline_gc); spin_lock(&l_mg->free_lock); @@ -1593,7 +1638,7 @@ static void pblk_line_put_ws(struct work_struct *work) struct pblk_line *line = line_put_ws->line; __pblk_line_put(pblk, line); - mempool_free(line_put_ws, pblk->gen_ws_pool); + mempool_free(line_put_ws, &pblk->gen_ws_pool); } void pblk_line_put(struct kref *ref) @@ -1610,7 +1655,7 @@ void pblk_line_put_wq(struct kref *ref) struct pblk *pblk = line->pblk; struct pblk_line_ws *line_put_ws; - line_put_ws = mempool_alloc(pblk->gen_ws_pool, GFP_ATOMIC); + line_put_ws = mempool_alloc(&pblk->gen_ws_pool, GFP_ATOMIC); if (!line_put_ws) return; @@ -1737,11 +1782,34 @@ void pblk_line_close_meta(struct pblk *pblk, struct pblk_line *line) spin_lock(&l_mg->close_lock); spin_lock(&line->lock); + + /* Update the in-memory start address for emeta, in case it has + * shifted due to write errors + */ + if (line->emeta_ssec != line->cur_sec) + line->emeta_ssec = line->cur_sec; + list_add_tail(&line->list, &l_mg->emeta_list); spin_unlock(&line->lock); spin_unlock(&l_mg->close_lock); pblk_line_should_sync_meta(pblk); + + +} + +static void pblk_save_lba_list(struct pblk *pblk, struct pblk_line *line) +{ + struct pblk_line_meta *lm = &pblk->lm; + struct pblk_line_mgmt *l_mg = &pblk->l_mg; + unsigned int lba_list_size = lm->emeta_len[2]; + struct pblk_w_err_gc *w_err_gc = line->w_err_gc; + struct pblk_emeta *emeta = line->emeta; + + w_err_gc->lba_list = pblk_malloc(lba_list_size, + l_mg->emeta_alloc_type, GFP_KERNEL); + memcpy(w_err_gc->lba_list, emeta_to_lbas(pblk, emeta->buf), + lba_list_size); } void pblk_line_close_ws(struct work_struct *work) @@ -1750,9 +1818,16 @@ void pblk_line_close_ws(struct work_struct *work) ws); struct pblk *pblk = line_ws->pblk; struct pblk_line *line = line_ws->line; + struct pblk_w_err_gc *w_err_gc = line->w_err_gc; + + /* Write errors makes the emeta start address stored in smeta invalid, + * so keep a copy of the lba list until we've gc'd the line + */ + if (w_err_gc->has_write_err) + pblk_save_lba_list(pblk, line); pblk_line_close(pblk, line); - mempool_free(line_ws, pblk->gen_ws_pool); + mempool_free(line_ws, &pblk->gen_ws_pool); } void pblk_gen_run_ws(struct pblk *pblk, struct pblk_line *line, void *priv, @@ -1761,7 +1836,7 @@ void pblk_gen_run_ws(struct pblk *pblk, struct pblk_line *line, void *priv, { struct pblk_line_ws *line_ws; - line_ws = mempool_alloc(pblk->gen_ws_pool, gfp_mask); + line_ws = mempool_alloc(&pblk->gen_ws_pool, gfp_mask); line_ws->pblk = pblk; line_ws->line = line; diff --git a/drivers/lightnvm/pblk-gc.c b/drivers/lightnvm/pblk-gc.c index 6851a5c67189..df88f1bdd921 100644 --- a/drivers/lightnvm/pblk-gc.c +++ b/drivers/lightnvm/pblk-gc.c @@ -129,6 +129,53 @@ out: kfree(gc_rq_ws); } +static __le64 *get_lba_list_from_emeta(struct pblk *pblk, + struct pblk_line *line) +{ + struct line_emeta *emeta_buf; + struct pblk_line_mgmt *l_mg = &pblk->l_mg; + struct pblk_line_meta *lm = &pblk->lm; + unsigned int lba_list_size = lm->emeta_len[2]; + __le64 *lba_list; + int ret; + + emeta_buf = pblk_malloc(lm->emeta_len[0], + l_mg->emeta_alloc_type, GFP_KERNEL); + if (!emeta_buf) + return NULL; + + ret = pblk_line_read_emeta(pblk, line, emeta_buf); + if (ret) { + pr_err("pblk: line %d read emeta failed (%d)\n", + line->id, ret); + pblk_mfree(emeta_buf, l_mg->emeta_alloc_type); + return NULL; + } + + /* If this read fails, it means that emeta is corrupted. + * For now, leave the line untouched. + * TODO: Implement a recovery routine that scans and moves + * all sectors on the line. + */ + + ret = pblk_recov_check_emeta(pblk, emeta_buf); + if (ret) { + pr_err("pblk: inconsistent emeta (line %d)\n", + line->id); + pblk_mfree(emeta_buf, l_mg->emeta_alloc_type); + return NULL; + } + + lba_list = pblk_malloc(lba_list_size, + l_mg->emeta_alloc_type, GFP_KERNEL); + if (lba_list) + memcpy(lba_list, emeta_to_lbas(pblk, emeta_buf), lba_list_size); + + pblk_mfree(emeta_buf, l_mg->emeta_alloc_type); + + return lba_list; +} + static void pblk_gc_line_prepare_ws(struct work_struct *work) { struct pblk_line_ws *line_ws = container_of(work, struct pblk_line_ws, @@ -138,46 +185,26 @@ static void pblk_gc_line_prepare_ws(struct work_struct *work) struct pblk_line_mgmt *l_mg = &pblk->l_mg; struct pblk_line_meta *lm = &pblk->lm; struct pblk_gc *gc = &pblk->gc; - struct line_emeta *emeta_buf; struct pblk_line_ws *gc_rq_ws; struct pblk_gc_rq *gc_rq; __le64 *lba_list; unsigned long *invalid_bitmap; int sec_left, nr_secs, bit; - int ret; invalid_bitmap = kmalloc(lm->sec_bitmap_len, GFP_KERNEL); if (!invalid_bitmap) goto fail_free_ws; - emeta_buf = pblk_malloc(lm->emeta_len[0], l_mg->emeta_alloc_type, - GFP_KERNEL); - if (!emeta_buf) { - pr_err("pblk: cannot use GC emeta\n"); - goto fail_free_bitmap; - } - - ret = pblk_line_read_emeta(pblk, line, emeta_buf); - if (ret) { - pr_err("pblk: line %d read emeta failed (%d)\n", line->id, ret); - goto fail_free_emeta; - } - - /* If this read fails, it means that emeta is corrupted. For now, leave - * the line untouched. TODO: Implement a recovery routine that scans and - * moves all sectors on the line. - */ - - ret = pblk_recov_check_emeta(pblk, emeta_buf); - if (ret) { - pr_err("pblk: inconsistent emeta (line %d)\n", line->id); - goto fail_free_emeta; - } - - lba_list = emeta_to_lbas(pblk, emeta_buf); - if (!lba_list) { - pr_err("pblk: could not interpret emeta (line %d)\n", line->id); - goto fail_free_emeta; + if (line->w_err_gc->has_write_err) { + lba_list = line->w_err_gc->lba_list; + line->w_err_gc->lba_list = NULL; + } else { + lba_list = get_lba_list_from_emeta(pblk, line); + if (!lba_list) { + pr_err("pblk: could not interpret emeta (line %d)\n", + line->id); + goto fail_free_ws; + } } spin_lock(&line->lock); @@ -187,14 +214,14 @@ static void pblk_gc_line_prepare_ws(struct work_struct *work) if (sec_left < 0) { pr_err("pblk: corrupted GC line (%d)\n", line->id); - goto fail_free_emeta; + goto fail_free_lba_list; } bit = -1; next_rq: gc_rq = kmalloc(sizeof(struct pblk_gc_rq), GFP_KERNEL); if (!gc_rq) - goto fail_free_emeta; + goto fail_free_lba_list; nr_secs = 0; do { @@ -240,7 +267,7 @@ next_rq: goto next_rq; out: - pblk_mfree(emeta_buf, l_mg->emeta_alloc_type); + pblk_mfree(lba_list, l_mg->emeta_alloc_type); kfree(line_ws); kfree(invalid_bitmap); @@ -251,9 +278,8 @@ out: fail_free_gc_rq: kfree(gc_rq); -fail_free_emeta: - pblk_mfree(emeta_buf, l_mg->emeta_alloc_type); -fail_free_bitmap: +fail_free_lba_list: + pblk_mfree(lba_list, l_mg->emeta_alloc_type); kfree(invalid_bitmap); fail_free_ws: kfree(line_ws); @@ -349,12 +375,14 @@ static struct pblk_line *pblk_gc_get_victim_line(struct pblk *pblk, static bool pblk_gc_should_run(struct pblk_gc *gc, struct pblk_rl *rl) { unsigned int nr_blocks_free, nr_blocks_need; + unsigned int werr_lines = atomic_read(&rl->werr_lines); nr_blocks_need = pblk_rl_high_thrs(rl); nr_blocks_free = pblk_rl_nr_free_blks(rl); /* This is not critical, no need to take lock here */ - return ((gc->gc_active) && (nr_blocks_need > nr_blocks_free)); + return ((werr_lines > 0) || + ((gc->gc_active) && (nr_blocks_need > nr_blocks_free))); } void pblk_gc_free_full_lines(struct pblk *pblk) @@ -649,7 +677,7 @@ fail_free_main_kthread: return ret; } -void pblk_gc_exit(struct pblk *pblk) +void pblk_gc_exit(struct pblk *pblk, bool graceful) { struct pblk_gc *gc = &pblk->gc; @@ -663,10 +691,12 @@ void pblk_gc_exit(struct pblk *pblk) if (gc->gc_reader_ts) kthread_stop(gc->gc_reader_ts); - flush_workqueue(gc->gc_reader_wq); - destroy_workqueue(gc->gc_reader_wq); + if (graceful) { + flush_workqueue(gc->gc_reader_wq); + flush_workqueue(gc->gc_line_reader_wq); + } - flush_workqueue(gc->gc_line_reader_wq); + destroy_workqueue(gc->gc_reader_wq); destroy_workqueue(gc->gc_line_reader_wq); if (gc->gc_writer_ts) diff --git a/drivers/lightnvm/pblk-init.c b/drivers/lightnvm/pblk-init.c index 91a5bc2556a3..ce561f5d48ce 100644 --- a/drivers/lightnvm/pblk-init.c +++ b/drivers/lightnvm/pblk-init.c @@ -20,10 +20,15 @@ #include "pblk.h" +unsigned int write_buffer_size; + +module_param(write_buffer_size, uint, 0644); +MODULE_PARM_DESC(write_buffer_size, "number of entries in a write buffer"); + static struct kmem_cache *pblk_ws_cache, *pblk_rec_cache, *pblk_g_rq_cache, *pblk_w_rq_cache; static DECLARE_RWSEM(pblk_lock); -struct bio_set *pblk_bio_set; +struct bio_set pblk_bio_set; static int pblk_rw_io(struct request_queue *q, struct pblk *pblk, struct bio *bio) @@ -127,10 +132,8 @@ static int pblk_l2p_recover(struct pblk *pblk, bool factory_init) if (!line) { /* Configure next line for user data */ line = pblk_line_get_first_data(pblk); - if (!line) { - pr_err("pblk: line list corrupted\n"); + if (!line) return -EFAULT; - } } return 0; @@ -141,6 +144,7 @@ static int pblk_l2p_init(struct pblk *pblk, bool factory_init) sector_t i; struct ppa_addr ppa; size_t map_size; + int ret = 0; map_size = pblk_trans_map_size(pblk); pblk->trans_map = vmalloc(map_size); @@ -152,7 +156,11 @@ static int pblk_l2p_init(struct pblk *pblk, bool factory_init) for (i = 0; i < pblk->rl.nr_secs; i++) pblk_trans_map_set(pblk, i, ppa); - return pblk_l2p_recover(pblk, factory_init); + ret = pblk_l2p_recover(pblk, factory_init); + if (ret) + vfree(pblk->trans_map); + + return ret; } static void pblk_rwb_free(struct pblk *pblk) @@ -169,10 +177,15 @@ static int pblk_rwb_init(struct pblk *pblk) struct nvm_tgt_dev *dev = pblk->dev; struct nvm_geo *geo = &dev->geo; struct pblk_rb_entry *entries; - unsigned long nr_entries; + unsigned long nr_entries, buffer_size; unsigned int power_size, power_seg_sz; - nr_entries = pblk_rb_calculate_size(pblk->pgs_in_buffer); + if (write_buffer_size && (write_buffer_size > pblk->pgs_in_buffer)) + buffer_size = write_buffer_size; + else + buffer_size = pblk->pgs_in_buffer; + + nr_entries = pblk_rb_calculate_size(buffer_size); entries = vzalloc(nr_entries * sizeof(struct pblk_rb_entry)); if (!entries) @@ -341,7 +354,7 @@ static int pblk_core_init(struct pblk *pblk) { struct nvm_tgt_dev *dev = pblk->dev; struct nvm_geo *geo = &dev->geo; - int max_write_ppas; + int ret, max_write_ppas; atomic64_set(&pblk->user_wa, 0); atomic64_set(&pblk->pad_wa, 0); @@ -375,33 +388,33 @@ static int pblk_core_init(struct pblk *pblk) goto fail_free_pad_dist; /* Internal bios can be at most the sectors signaled by the device. */ - pblk->page_bio_pool = mempool_create_page_pool(NVM_MAX_VLBA, 0); - if (!pblk->page_bio_pool) + ret = mempool_init_page_pool(&pblk->page_bio_pool, NVM_MAX_VLBA, 0); + if (ret) goto free_global_caches; - pblk->gen_ws_pool = mempool_create_slab_pool(PBLK_GEN_WS_POOL_SIZE, - pblk_ws_cache); - if (!pblk->gen_ws_pool) + ret = mempool_init_slab_pool(&pblk->gen_ws_pool, PBLK_GEN_WS_POOL_SIZE, + pblk_ws_cache); + if (ret) goto free_page_bio_pool; - pblk->rec_pool = mempool_create_slab_pool(geo->all_luns, - pblk_rec_cache); - if (!pblk->rec_pool) + ret = mempool_init_slab_pool(&pblk->rec_pool, geo->all_luns, + pblk_rec_cache); + if (ret) goto free_gen_ws_pool; - pblk->r_rq_pool = mempool_create_slab_pool(geo->all_luns, - pblk_g_rq_cache); - if (!pblk->r_rq_pool) + ret = mempool_init_slab_pool(&pblk->r_rq_pool, geo->all_luns, + pblk_g_rq_cache); + if (ret) goto free_rec_pool; - pblk->e_rq_pool = mempool_create_slab_pool(geo->all_luns, - pblk_g_rq_cache); - if (!pblk->e_rq_pool) + ret = mempool_init_slab_pool(&pblk->e_rq_pool, geo->all_luns, + pblk_g_rq_cache); + if (ret) goto free_r_rq_pool; - pblk->w_rq_pool = mempool_create_slab_pool(geo->all_luns, - pblk_w_rq_cache); - if (!pblk->w_rq_pool) + ret = mempool_init_slab_pool(&pblk->w_rq_pool, geo->all_luns, + pblk_w_rq_cache); + if (ret) goto free_e_rq_pool; pblk->close_wq = alloc_workqueue("pblk-close-wq", @@ -423,6 +436,7 @@ static int pblk_core_init(struct pblk *pblk) goto free_r_end_wq; INIT_LIST_HEAD(&pblk->compl_list); + INIT_LIST_HEAD(&pblk->resubmit_list); return 0; @@ -433,17 +447,17 @@ free_bb_wq: free_close_wq: destroy_workqueue(pblk->close_wq); free_w_rq_pool: - mempool_destroy(pblk->w_rq_pool); + mempool_exit(&pblk->w_rq_pool); free_e_rq_pool: - mempool_destroy(pblk->e_rq_pool); + mempool_exit(&pblk->e_rq_pool); free_r_rq_pool: - mempool_destroy(pblk->r_rq_pool); + mempool_exit(&pblk->r_rq_pool); free_rec_pool: - mempool_destroy(pblk->rec_pool); + mempool_exit(&pblk->rec_pool); free_gen_ws_pool: - mempool_destroy(pblk->gen_ws_pool); + mempool_exit(&pblk->gen_ws_pool); free_page_bio_pool: - mempool_destroy(pblk->page_bio_pool); + mempool_exit(&pblk->page_bio_pool); free_global_caches: pblk_free_global_caches(pblk); fail_free_pad_dist: @@ -462,12 +476,12 @@ static void pblk_core_free(struct pblk *pblk) if (pblk->bb_wq) destroy_workqueue(pblk->bb_wq); - mempool_destroy(pblk->page_bio_pool); - mempool_destroy(pblk->gen_ws_pool); - mempool_destroy(pblk->rec_pool); - mempool_destroy(pblk->r_rq_pool); - mempool_destroy(pblk->e_rq_pool); - mempool_destroy(pblk->w_rq_pool); + mempool_exit(&pblk->page_bio_pool); + mempool_exit(&pblk->gen_ws_pool); + mempool_exit(&pblk->rec_pool); + mempool_exit(&pblk->r_rq_pool); + mempool_exit(&pblk->e_rq_pool); + mempool_exit(&pblk->w_rq_pool); pblk_free_global_caches(pblk); kfree(pblk->pad_dist); @@ -489,11 +503,17 @@ static void pblk_line_mg_free(struct pblk *pblk) } } -static void pblk_line_meta_free(struct pblk_line *line) +static void pblk_line_meta_free(struct pblk_line_mgmt *l_mg, + struct pblk_line *line) { + struct pblk_w_err_gc *w_err_gc = line->w_err_gc; + kfree(line->blk_bitmap); kfree(line->erase_bitmap); kfree(line->chks); + + pblk_mfree(w_err_gc->lba_list, l_mg->emeta_alloc_type); + kfree(w_err_gc); } static void pblk_lines_free(struct pblk *pblk) @@ -506,8 +526,8 @@ static void pblk_lines_free(struct pblk *pblk) for (i = 0; i < l_mg->nr_lines; i++) { line = &pblk->lines[i]; - pblk_line_free(pblk, line); - pblk_line_meta_free(line); + pblk_line_free(line); + pblk_line_meta_free(l_mg, line); } spin_unlock(&l_mg->free_lock); @@ -748,14 +768,14 @@ static int pblk_setup_line_meta_20(struct pblk *pblk, struct pblk_line *line, chunk->cnlb = chunk_meta->cnlb; chunk->wp = chunk_meta->wp; - if (!(chunk->state & NVM_CHK_ST_OFFLINE)) - continue; - if (chunk->type & NVM_CHK_TP_SZ_SPEC) { WARN_ONCE(1, "pblk: custom-sized chunks unsupported\n"); continue; } + if (!(chunk->state & NVM_CHK_ST_OFFLINE)) + continue; + set_bit(pos, line->blk_bitmap); nr_bad_chks++; } @@ -809,20 +829,28 @@ static int pblk_alloc_line_meta(struct pblk *pblk, struct pblk_line *line) return -ENOMEM; line->erase_bitmap = kzalloc(lm->blk_bitmap_len, GFP_KERNEL); - if (!line->erase_bitmap) { - kfree(line->blk_bitmap); - return -ENOMEM; - } + if (!line->erase_bitmap) + goto free_blk_bitmap; + line->chks = kmalloc(lm->blk_per_line * sizeof(struct nvm_chk_meta), GFP_KERNEL); - if (!line->chks) { - kfree(line->erase_bitmap); - kfree(line->blk_bitmap); - return -ENOMEM; - } + if (!line->chks) + goto free_erase_bitmap; + + line->w_err_gc = kzalloc(sizeof(struct pblk_w_err_gc), GFP_KERNEL); + if (!line->w_err_gc) + goto free_chks; return 0; + +free_chks: + kfree(line->chks); +free_erase_bitmap: + kfree(line->erase_bitmap); +free_blk_bitmap: + kfree(line->blk_bitmap); + return -ENOMEM; } static int pblk_line_mg_init(struct pblk *pblk) @@ -847,12 +875,14 @@ static int pblk_line_mg_init(struct pblk *pblk) INIT_LIST_HEAD(&l_mg->gc_mid_list); INIT_LIST_HEAD(&l_mg->gc_low_list); INIT_LIST_HEAD(&l_mg->gc_empty_list); + INIT_LIST_HEAD(&l_mg->gc_werr_list); INIT_LIST_HEAD(&l_mg->emeta_list); - l_mg->gc_lists[0] = &l_mg->gc_high_list; - l_mg->gc_lists[1] = &l_mg->gc_mid_list; - l_mg->gc_lists[2] = &l_mg->gc_low_list; + l_mg->gc_lists[0] = &l_mg->gc_werr_list; + l_mg->gc_lists[1] = &l_mg->gc_high_list; + l_mg->gc_lists[2] = &l_mg->gc_mid_list; + l_mg->gc_lists[3] = &l_mg->gc_low_list; spin_lock_init(&l_mg->free_lock); spin_lock_init(&l_mg->close_lock); @@ -1047,6 +1077,11 @@ static int pblk_lines_init(struct pblk *pblk) nr_free_chks += pblk_setup_line_meta(pblk, line, chunk_meta, i); } + if (!nr_free_chks) { + pr_err("pblk: too many bad blocks prevent for sane instance\n"); + return -EINTR; + } + pblk_set_provision(pblk, nr_free_chks); kfree(chunk_meta); @@ -1054,7 +1089,7 @@ static int pblk_lines_init(struct pblk *pblk) fail_free_lines: while (--i >= 0) - pblk_line_meta_free(&pblk->lines[i]); + pblk_line_meta_free(l_mg, &pblk->lines[i]); kfree(pblk->lines); fail_free_chunk_meta: kfree(chunk_meta); @@ -1110,23 +1145,25 @@ static void pblk_free(struct pblk *pblk) kfree(pblk); } -static void pblk_tear_down(struct pblk *pblk) +static void pblk_tear_down(struct pblk *pblk, bool graceful) { - pblk_pipeline_stop(pblk); + if (graceful) + __pblk_pipeline_flush(pblk); + __pblk_pipeline_stop(pblk); pblk_writer_stop(pblk); pblk_rb_sync_l2p(&pblk->rwb); pblk_rl_free(&pblk->rl); - pr_debug("pblk: consistent tear down\n"); + pr_debug("pblk: consistent tear down (graceful:%d)\n", graceful); } -static void pblk_exit(void *private) +static void pblk_exit(void *private, bool graceful) { struct pblk *pblk = private; down_write(&pblk_lock); - pblk_gc_exit(pblk); - pblk_tear_down(pblk); + pblk_gc_exit(pblk, graceful); + pblk_tear_down(pblk, graceful); #ifdef CONFIG_NVM_DEBUG pr_info("pblk exit: L2P CRC: %x\n", pblk_l2p_crc(pblk)); @@ -1175,6 +1212,7 @@ static void *pblk_init(struct nvm_tgt_dev *dev, struct gendisk *tdisk, pblk->state = PBLK_STATE_RUNNING; pblk->gc.gc_enabled = 0; + spin_lock_init(&pblk->resubmit_lock); spin_lock_init(&pblk->trans_lock); spin_lock_init(&pblk->lock); @@ -1297,18 +1335,18 @@ static int __init pblk_module_init(void) { int ret; - pblk_bio_set = bioset_create(BIO_POOL_SIZE, 0, 0); - if (!pblk_bio_set) - return -ENOMEM; + ret = bioset_init(&pblk_bio_set, BIO_POOL_SIZE, 0, 0); + if (ret) + return ret; ret = nvm_register_tgt_type(&tt_pblk); if (ret) - bioset_free(pblk_bio_set); + bioset_exit(&pblk_bio_set); return ret; } static void pblk_module_exit(void) { - bioset_free(pblk_bio_set); + bioset_exit(&pblk_bio_set); nvm_unregister_tgt_type(&tt_pblk); } diff --git a/drivers/lightnvm/pblk-map.c b/drivers/lightnvm/pblk-map.c index 20dbaa89c9df..953ca31dda68 100644 --- a/drivers/lightnvm/pblk-map.c +++ b/drivers/lightnvm/pblk-map.c @@ -18,11 +18,11 @@ #include "pblk.h" -static void pblk_map_page_data(struct pblk *pblk, unsigned int sentry, - struct ppa_addr *ppa_list, - unsigned long *lun_bitmap, - struct pblk_sec_meta *meta_list, - unsigned int valid_secs) +static int pblk_map_page_data(struct pblk *pblk, unsigned int sentry, + struct ppa_addr *ppa_list, + unsigned long *lun_bitmap, + struct pblk_sec_meta *meta_list, + unsigned int valid_secs) { struct pblk_line *line = pblk_line_get_data(pblk); struct pblk_emeta *emeta; @@ -35,8 +35,14 @@ static void pblk_map_page_data(struct pblk *pblk, unsigned int sentry, if (pblk_line_is_full(line)) { struct pblk_line *prev_line = line; + /* If we cannot allocate a new line, make sure to store metadata + * on current line and then fail + */ line = pblk_line_replace_data(pblk); pblk_line_close_meta(pblk, prev_line); + + if (!line) + return -EINTR; } emeta = line->emeta; @@ -74,6 +80,7 @@ static void pblk_map_page_data(struct pblk *pblk, unsigned int sentry, } pblk_down_rq(pblk, ppa_list, nr_secs, lun_bitmap); + return 0; } void pblk_map_rq(struct pblk *pblk, struct nvm_rq *rqd, unsigned int sentry, @@ -87,8 +94,12 @@ void pblk_map_rq(struct pblk *pblk, struct nvm_rq *rqd, unsigned int sentry, for (i = off; i < rqd->nr_ppas; i += min) { map_secs = (i + min > valid_secs) ? (valid_secs % min) : min; - pblk_map_page_data(pblk, sentry + i, &rqd->ppa_list[i], - lun_bitmap, &meta_list[i], map_secs); + if (pblk_map_page_data(pblk, sentry + i, &rqd->ppa_list[i], + lun_bitmap, &meta_list[i], map_secs)) { + bio_put(rqd->bio); + pblk_free_rqd(pblk, rqd, PBLK_WRITE); + pblk_pipeline_stop(pblk); + } } } @@ -108,8 +119,12 @@ void pblk_map_erase_rq(struct pblk *pblk, struct nvm_rq *rqd, for (i = 0; i < rqd->nr_ppas; i += min) { map_secs = (i + min > valid_secs) ? (valid_secs % min) : min; - pblk_map_page_data(pblk, sentry + i, &rqd->ppa_list[i], - lun_bitmap, &meta_list[i], map_secs); + if (pblk_map_page_data(pblk, sentry + i, &rqd->ppa_list[i], + lun_bitmap, &meta_list[i], map_secs)) { + bio_put(rqd->bio); + pblk_free_rqd(pblk, rqd, PBLK_WRITE); + pblk_pipeline_stop(pblk); + } erase_lun = pblk_ppa_to_pos(geo, rqd->ppa_list[i]); diff --git a/drivers/lightnvm/pblk-rb.c b/drivers/lightnvm/pblk-rb.c index 52fdd85dbc97..00cd1f20a196 100644 --- a/drivers/lightnvm/pblk-rb.c +++ b/drivers/lightnvm/pblk-rb.c @@ -142,10 +142,9 @@ static void clean_wctx(struct pblk_w_ctx *w_ctx) { int flags; -try: flags = READ_ONCE(w_ctx->flags); - if (!(flags & PBLK_SUBMITTED_ENTRY)) - goto try; + WARN_ONCE(!(flags & PBLK_SUBMITTED_ENTRY), + "pblk: overwriting unsubmitted data\n"); /* Release flags on context. Protect from writes and reads */ smp_store_release(&w_ctx->flags, PBLK_WRITABLE_ENTRY); @@ -350,7 +349,7 @@ void pblk_rb_write_entry_gc(struct pblk_rb *rb, void *data, } static int pblk_rb_flush_point_set(struct pblk_rb *rb, struct bio *bio, - unsigned int pos) + unsigned int pos) { struct pblk_rb_entry *entry; unsigned int sync, flush_point; @@ -420,7 +419,7 @@ void pblk_rb_flush(struct pblk_rb *rb) if (pblk_rb_flush_point_set(rb, NULL, mem)) return; - pblk_write_should_kick(pblk); + pblk_write_kick(pblk); } static int pblk_rb_may_write_flush(struct pblk_rb *rb, unsigned int nr_entries, @@ -504,45 +503,6 @@ int pblk_rb_may_write_gc(struct pblk_rb *rb, unsigned int nr_entries, } /* - * The caller of this function must ensure that the backpointer will not - * overwrite the entries passed on the list. - */ -unsigned int pblk_rb_read_to_bio_list(struct pblk_rb *rb, struct bio *bio, - struct list_head *list, - unsigned int max) -{ - struct pblk_rb_entry *entry, *tentry; - struct page *page; - unsigned int read = 0; - int ret; - - list_for_each_entry_safe(entry, tentry, list, index) { - if (read > max) { - pr_err("pblk: too many entries on list\n"); - goto out; - } - - page = virt_to_page(entry->data); - if (!page) { - pr_err("pblk: could not allocate write bio page\n"); - goto out; - } - - ret = bio_add_page(bio, page, rb->seg_size, 0); - if (ret != rb->seg_size) { - pr_err("pblk: could not add page to write bio\n"); - goto out; - } - - list_del(&entry->index); - read++; - } - -out: - return read; -} - -/* * Read available entries on rb and add them to the given bio. To avoid a memory * copy, a page reference to the write buffer is used to be added to the bio. * diff --git a/drivers/lightnvm/pblk-read.c b/drivers/lightnvm/pblk-read.c index 9eee10f69df0..18694694e5f0 100644 --- a/drivers/lightnvm/pblk-read.c +++ b/drivers/lightnvm/pblk-read.c @@ -39,10 +39,10 @@ static int pblk_read_from_cache(struct pblk *pblk, struct bio *bio, } static void pblk_read_ppalist_rq(struct pblk *pblk, struct nvm_rq *rqd, - sector_t blba, unsigned long *read_bitmap) + struct bio *bio, sector_t blba, + unsigned long *read_bitmap) { struct pblk_sec_meta *meta_list = rqd->meta_list; - struct bio *bio = rqd->bio; struct ppa_addr ppas[PBLK_MAX_REQ_ADDRS]; int nr_secs = rqd->nr_ppas; bool advanced_bio = false; @@ -102,32 +102,69 @@ next: #endif } -static int pblk_submit_read_io(struct pblk *pblk, struct nvm_rq *rqd) + +static void pblk_read_check_seq(struct pblk *pblk, struct nvm_rq *rqd, + sector_t blba) { - int err; + struct pblk_sec_meta *meta_lba_list = rqd->meta_list; + int nr_lbas = rqd->nr_ppas; + int i; - err = pblk_submit_io(pblk, rqd); - if (err) - return NVM_IO_ERR; + for (i = 0; i < nr_lbas; i++) { + u64 lba = le64_to_cpu(meta_lba_list[i].lba); + + if (lba == ADDR_EMPTY) + continue; + + if (lba != blba + i) { +#ifdef CONFIG_NVM_DEBUG + struct ppa_addr *p; - return NVM_IO_OK; + p = (nr_lbas == 1) ? &rqd->ppa_list[i] : &rqd->ppa_addr; + print_ppa(&pblk->dev->geo, p, "seq", i); +#endif + pr_err("pblk: corrupted read LBA (%llu/%llu)\n", + lba, (u64)blba + i); + WARN_ON(1); + } + } } -static void pblk_read_check(struct pblk *pblk, struct nvm_rq *rqd, - sector_t blba) +/* + * There can be holes in the lba list. + */ +static void pblk_read_check_rand(struct pblk *pblk, struct nvm_rq *rqd, + u64 *lba_list, int nr_lbas) { - struct pblk_sec_meta *meta_list = rqd->meta_list; - int nr_lbas = rqd->nr_ppas; - int i; + struct pblk_sec_meta *meta_lba_list = rqd->meta_list; + int i, j; - for (i = 0; i < nr_lbas; i++) { - u64 lba = le64_to_cpu(meta_list[i].lba); + for (i = 0, j = 0; i < nr_lbas; i++) { + u64 lba = lba_list[i]; + u64 meta_lba; if (lba == ADDR_EMPTY) continue; - WARN(lba != blba + i, "pblk: corrupted read LBA\n"); + meta_lba = le64_to_cpu(meta_lba_list[j].lba); + + if (lba != meta_lba) { +#ifdef CONFIG_NVM_DEBUG + struct ppa_addr *p; + int nr_ppas = rqd->nr_ppas; + + p = (nr_ppas == 1) ? &rqd->ppa_list[j] : &rqd->ppa_addr; + print_ppa(&pblk->dev->geo, p, "seq", j); +#endif + pr_err("pblk: corrupted read LBA (%llu/%llu)\n", + lba, meta_lba); + WARN_ON(1); + } + + j++; } + + WARN_ONCE(j != rqd->nr_ppas, "pblk: corrupted random request\n"); } static void pblk_read_put_rqd_kref(struct pblk *pblk, struct nvm_rq *rqd) @@ -152,7 +189,6 @@ static void pblk_end_user_read(struct bio *bio) WARN_ONCE(bio->bi_status, "pblk: corrupted read bio\n"); #endif bio_endio(bio); - bio_put(bio); } static void __pblk_end_io_read(struct pblk *pblk, struct nvm_rq *rqd, @@ -160,23 +196,18 @@ static void __pblk_end_io_read(struct pblk *pblk, struct nvm_rq *rqd, { struct nvm_tgt_dev *dev = pblk->dev; struct pblk_g_ctx *r_ctx = nvm_rq_to_pdu(rqd); - struct bio *bio = rqd->bio; + struct bio *int_bio = rqd->bio; unsigned long start_time = r_ctx->start_time; generic_end_io_acct(dev->q, READ, &pblk->disk->part0, start_time); if (rqd->error) pblk_log_read_err(pblk, rqd); -#ifdef CONFIG_NVM_DEBUG - else - WARN_ONCE(bio->bi_status, "pblk: corrupted read error\n"); -#endif - pblk_read_check(pblk, rqd, r_ctx->lba); + pblk_read_check_seq(pblk, rqd, r_ctx->lba); - bio_put(bio); - if (r_ctx->private) - pblk_end_user_read((struct bio *)r_ctx->private); + if (int_bio) + bio_put(int_bio); if (put_line) pblk_read_put_rqd_kref(pblk, rqd); @@ -193,16 +224,19 @@ static void __pblk_end_io_read(struct pblk *pblk, struct nvm_rq *rqd, static void pblk_end_io_read(struct nvm_rq *rqd) { struct pblk *pblk = rqd->private; + struct pblk_g_ctx *r_ctx = nvm_rq_to_pdu(rqd); + struct bio *bio = (struct bio *)r_ctx->private; + pblk_end_user_read(bio); __pblk_end_io_read(pblk, rqd, true); } -static int pblk_partial_read_bio(struct pblk *pblk, struct nvm_rq *rqd, - unsigned int bio_init_idx, - unsigned long *read_bitmap) +static int pblk_partial_read(struct pblk *pblk, struct nvm_rq *rqd, + struct bio *orig_bio, unsigned int bio_init_idx, + unsigned long *read_bitmap) { - struct bio *new_bio, *bio = rqd->bio; struct pblk_sec_meta *meta_list = rqd->meta_list; + struct bio *new_bio; struct bio_vec src_bv, dst_bv; void *ppa_ptr = NULL; void *src_p, *dst_p; @@ -219,11 +253,11 @@ static int pblk_partial_read_bio(struct pblk *pblk, struct nvm_rq *rqd, new_bio = bio_alloc(GFP_KERNEL, nr_holes); if (pblk_bio_add_pages(pblk, new_bio, GFP_KERNEL, nr_holes)) - goto err; + goto fail_add_pages; if (nr_holes != new_bio->bi_vcnt) { pr_err("pblk: malformed bio\n"); - goto err; + goto fail; } for (i = 0; i < nr_secs; i++) @@ -246,7 +280,7 @@ static int pblk_partial_read_bio(struct pblk *pblk, struct nvm_rq *rqd, if (ret) { bio_put(rqd->bio); pr_err("pblk: sync read IO submission failed\n"); - goto err; + goto fail; } if (rqd->error) { @@ -282,7 +316,7 @@ static int pblk_partial_read_bio(struct pblk *pblk, struct nvm_rq *rqd, meta_list[hole].lba = lba_list_media[i]; src_bv = new_bio->bi_io_vec[i++]; - dst_bv = bio->bi_io_vec[bio_init_idx + hole]; + dst_bv = orig_bio->bi_io_vec[bio_init_idx + hole]; src_p = kmap_atomic(src_bv.bv_page); dst_p = kmap_atomic(dst_bv.bv_page); @@ -294,35 +328,33 @@ static int pblk_partial_read_bio(struct pblk *pblk, struct nvm_rq *rqd, kunmap_atomic(src_p); kunmap_atomic(dst_p); - mempool_free(src_bv.bv_page, pblk->page_bio_pool); + mempool_free(src_bv.bv_page, &pblk->page_bio_pool); hole = find_next_zero_bit(read_bitmap, nr_secs, hole + 1); } while (hole < nr_secs); bio_put(new_bio); - /* Complete the original bio and associated request */ - bio_endio(bio); - rqd->bio = bio; + /* restore original request */ + rqd->bio = NULL; rqd->nr_ppas = nr_secs; __pblk_end_io_read(pblk, rqd, false); - return NVM_IO_OK; - -err: - pr_err("pblk: failed to perform partial read\n"); + return NVM_IO_DONE; +fail: /* Free allocated pages in new bio */ - pblk_bio_free_pages(pblk, bio, 0, new_bio->bi_vcnt); + pblk_bio_free_pages(pblk, new_bio, 0, new_bio->bi_vcnt); +fail_add_pages: + pr_err("pblk: failed to perform partial read\n"); __pblk_end_io_read(pblk, rqd, false); return NVM_IO_ERR; } -static void pblk_read_rq(struct pblk *pblk, struct nvm_rq *rqd, +static void pblk_read_rq(struct pblk *pblk, struct nvm_rq *rqd, struct bio *bio, sector_t lba, unsigned long *read_bitmap) { struct pblk_sec_meta *meta_list = rqd->meta_list; - struct bio *bio = rqd->bio; struct ppa_addr ppa; pblk_lookup_l2p_seq(pblk, &ppa, lba, 1); @@ -386,14 +418,15 @@ int pblk_submit_read(struct pblk *pblk, struct bio *bio) rqd = pblk_alloc_rqd(pblk, PBLK_READ); rqd->opcode = NVM_OP_PREAD; - rqd->bio = bio; rqd->nr_ppas = nr_secs; + rqd->bio = NULL; /* cloned bio if needed */ rqd->private = pblk; rqd->end_io = pblk_end_io_read; r_ctx = nvm_rq_to_pdu(rqd); r_ctx->start_time = jiffies; r_ctx->lba = blba; + r_ctx->private = bio; /* original bio */ /* Save the index for this bio's start. This is needed in case * we need to fill a partial read. @@ -411,17 +444,15 @@ int pblk_submit_read(struct pblk *pblk, struct bio *bio) rqd->ppa_list = rqd->meta_list + pblk_dma_meta_size; rqd->dma_ppa_list = rqd->dma_meta_list + pblk_dma_meta_size; - pblk_read_ppalist_rq(pblk, rqd, blba, &read_bitmap); + pblk_read_ppalist_rq(pblk, rqd, bio, blba, &read_bitmap); } else { - pblk_read_rq(pblk, rqd, blba, &read_bitmap); + pblk_read_rq(pblk, rqd, bio, blba, &read_bitmap); } - bio_get(bio); if (bitmap_full(&read_bitmap, nr_secs)) { - bio_endio(bio); atomic_inc(&pblk->inflight_io); __pblk_end_io_read(pblk, rqd, false); - return NVM_IO_OK; + return NVM_IO_DONE; } /* All sectors are to be read from the device */ @@ -429,20 +460,17 @@ int pblk_submit_read(struct pblk *pblk, struct bio *bio) struct bio *int_bio = NULL; /* Clone read bio to deal with read errors internally */ - int_bio = bio_clone_fast(bio, GFP_KERNEL, pblk_bio_set); + int_bio = bio_clone_fast(bio, GFP_KERNEL, &pblk_bio_set); if (!int_bio) { pr_err("pblk: could not clone read bio\n"); goto fail_end_io; } rqd->bio = int_bio; - r_ctx->private = bio; - ret = pblk_submit_read_io(pblk, rqd); - if (ret) { + if (pblk_submit_io(pblk, rqd)) { pr_err("pblk: read IO submission failed\n"); - if (int_bio) - bio_put(int_bio); + ret = NVM_IO_ERR; goto fail_end_io; } @@ -452,7 +480,7 @@ int pblk_submit_read(struct pblk *pblk, struct bio *bio) /* The read bio request could be partially filled by the write buffer, * but there are some holes that need to be read from the drive. */ - return pblk_partial_read_bio(pblk, rqd, bio_init_idx, &read_bitmap); + return pblk_partial_read(pblk, rqd, bio, bio_init_idx, &read_bitmap); fail_rqd_free: pblk_free_rqd(pblk, rqd, PBLK_READ); @@ -585,6 +613,8 @@ int pblk_submit_read_gc(struct pblk *pblk, struct pblk_gc_rq *gc_rq) goto err_free_bio; } + pblk_read_check_rand(pblk, &rqd, gc_rq->lba_list, gc_rq->nr_secs); + atomic_dec(&pblk->inflight_io); if (rqd.error) { diff --git a/drivers/lightnvm/pblk-recovery.c b/drivers/lightnvm/pblk-recovery.c index 3e079c2afa6e..598342833d0d 100644 --- a/drivers/lightnvm/pblk-recovery.c +++ b/drivers/lightnvm/pblk-recovery.c @@ -16,97 +16,6 @@ #include "pblk.h" -void pblk_submit_rec(struct work_struct *work) -{ - struct pblk_rec_ctx *recovery = - container_of(work, struct pblk_rec_ctx, ws_rec); - struct pblk *pblk = recovery->pblk; - struct nvm_rq *rqd = recovery->rqd; - struct pblk_c_ctx *c_ctx = nvm_rq_to_pdu(rqd); - struct bio *bio; - unsigned int nr_rec_secs; - unsigned int pgs_read; - int ret; - - nr_rec_secs = bitmap_weight((unsigned long int *)&rqd->ppa_status, - NVM_MAX_VLBA); - - bio = bio_alloc(GFP_KERNEL, nr_rec_secs); - - bio->bi_iter.bi_sector = 0; - bio_set_op_attrs(bio, REQ_OP_WRITE, 0); - rqd->bio = bio; - rqd->nr_ppas = nr_rec_secs; - - pgs_read = pblk_rb_read_to_bio_list(&pblk->rwb, bio, &recovery->failed, - nr_rec_secs); - if (pgs_read != nr_rec_secs) { - pr_err("pblk: could not read recovery entries\n"); - goto err; - } - - if (pblk_setup_w_rec_rq(pblk, rqd, c_ctx)) { - pr_err("pblk: could not setup recovery request\n"); - goto err; - } - -#ifdef CONFIG_NVM_DEBUG - atomic_long_add(nr_rec_secs, &pblk->recov_writes); -#endif - - ret = pblk_submit_io(pblk, rqd); - if (ret) { - pr_err("pblk: I/O submission failed: %d\n", ret); - goto err; - } - - mempool_free(recovery, pblk->rec_pool); - return; - -err: - bio_put(bio); - pblk_free_rqd(pblk, rqd, PBLK_WRITE); -} - -int pblk_recov_setup_rq(struct pblk *pblk, struct pblk_c_ctx *c_ctx, - struct pblk_rec_ctx *recovery, u64 *comp_bits, - unsigned int comp) -{ - struct nvm_rq *rec_rqd; - struct pblk_c_ctx *rec_ctx; - int nr_entries = c_ctx->nr_valid + c_ctx->nr_padded; - - rec_rqd = pblk_alloc_rqd(pblk, PBLK_WRITE); - rec_ctx = nvm_rq_to_pdu(rec_rqd); - - /* Copy completion bitmap, but exclude the first X completed entries */ - bitmap_shift_right((unsigned long int *)&rec_rqd->ppa_status, - (unsigned long int *)comp_bits, - comp, NVM_MAX_VLBA); - - /* Save the context for the entries that need to be re-written and - * update current context with the completed entries. - */ - rec_ctx->sentry = pblk_rb_wrap_pos(&pblk->rwb, c_ctx->sentry + comp); - if (comp >= c_ctx->nr_valid) { - rec_ctx->nr_valid = 0; - rec_ctx->nr_padded = nr_entries - comp; - - c_ctx->nr_padded = comp - c_ctx->nr_valid; - } else { - rec_ctx->nr_valid = c_ctx->nr_valid - comp; - rec_ctx->nr_padded = c_ctx->nr_padded; - - c_ctx->nr_valid = comp; - c_ctx->nr_padded = 0; - } - - recovery->rqd = rec_rqd; - recovery->pblk = pblk; - - return 0; -} - int pblk_recov_check_emeta(struct pblk *pblk, struct line_emeta *emeta_buf) { u32 crc; @@ -865,18 +774,30 @@ static void pblk_recov_wa_counters(struct pblk *pblk, } static int pblk_line_was_written(struct pblk_line *line, - struct pblk_line_meta *lm) + struct pblk *pblk) { - int i; - int state_mask = NVM_CHK_ST_OFFLINE | NVM_CHK_ST_FREE; + struct pblk_line_meta *lm = &pblk->lm; + struct nvm_tgt_dev *dev = pblk->dev; + struct nvm_geo *geo = &dev->geo; + struct nvm_chk_meta *chunk; + struct ppa_addr bppa; + int smeta_blk; - for (i = 0; i < lm->blk_per_line; i++) { - if (!(line->chks[i].state & state_mask)) - return 1; - } + if (line->state == PBLK_LINESTATE_BAD) + return 0; - return 0; + smeta_blk = find_first_zero_bit(line->blk_bitmap, lm->blk_per_line); + if (smeta_blk >= lm->blk_per_line) + return 0; + + bppa = pblk->luns[smeta_blk].bppa; + chunk = &line->chks[pblk_ppa_to_pos(geo, bppa)]; + + if (chunk->state & NVM_CHK_ST_FREE) + return 0; + + return 1; } struct pblk_line *pblk_recov_l2p(struct pblk *pblk) @@ -915,7 +836,7 @@ struct pblk_line *pblk_recov_l2p(struct pblk *pblk) line->lun_bitmap = ((void *)(smeta_buf)) + sizeof(struct line_smeta); - if (!pblk_line_was_written(line, lm)) + if (!pblk_line_was_written(line, pblk)) continue; /* Lines that cannot be read are assumed as not written here */ diff --git a/drivers/lightnvm/pblk-rl.c b/drivers/lightnvm/pblk-rl.c index 883a7113b19d..6a0616a6fcaf 100644 --- a/drivers/lightnvm/pblk-rl.c +++ b/drivers/lightnvm/pblk-rl.c @@ -73,6 +73,16 @@ void pblk_rl_user_in(struct pblk_rl *rl, int nr_entries) pblk_rl_kick_u_timer(rl); } +void pblk_rl_werr_line_in(struct pblk_rl *rl) +{ + atomic_inc(&rl->werr_lines); +} + +void pblk_rl_werr_line_out(struct pblk_rl *rl) +{ + atomic_dec(&rl->werr_lines); +} + void pblk_rl_gc_in(struct pblk_rl *rl, int nr_entries) { atomic_add(nr_entries, &rl->rb_gc_cnt); @@ -99,11 +109,21 @@ static void __pblk_rl_update_rates(struct pblk_rl *rl, { struct pblk *pblk = container_of(rl, struct pblk, rl); int max = rl->rb_budget; + int werr_gc_needed = atomic_read(&rl->werr_lines); if (free_blocks >= rl->high) { - rl->rb_user_max = max; - rl->rb_gc_max = 0; - rl->rb_state = PBLK_RL_HIGH; + if (werr_gc_needed) { + /* Allocate a small budget for recovering + * lines with write errors + */ + rl->rb_gc_max = 1 << rl->rb_windows_pw; + rl->rb_user_max = max - rl->rb_gc_max; + rl->rb_state = PBLK_RL_WERR; + } else { + rl->rb_user_max = max; + rl->rb_gc_max = 0; + rl->rb_state = PBLK_RL_OFF; + } } else if (free_blocks < rl->high) { int shift = rl->high_pw - rl->rb_windows_pw; int user_windows = free_blocks >> shift; @@ -124,7 +144,7 @@ static void __pblk_rl_update_rates(struct pblk_rl *rl, rl->rb_state = PBLK_RL_LOW; } - if (rl->rb_state == (PBLK_RL_MID | PBLK_RL_LOW)) + if (rl->rb_state != PBLK_RL_OFF) pblk_gc_should_start(pblk); else pblk_gc_should_stop(pblk); @@ -221,6 +241,7 @@ void pblk_rl_init(struct pblk_rl *rl, int budget) atomic_set(&rl->rb_user_cnt, 0); atomic_set(&rl->rb_gc_cnt, 0); atomic_set(&rl->rb_space, -1); + atomic_set(&rl->werr_lines, 0); timer_setup(&rl->u_timer, pblk_rl_u_timer, 0); diff --git a/drivers/lightnvm/pblk-sysfs.c b/drivers/lightnvm/pblk-sysfs.c index e61909af23a5..88a0a7c407aa 100644 --- a/drivers/lightnvm/pblk-sysfs.c +++ b/drivers/lightnvm/pblk-sysfs.c @@ -173,6 +173,8 @@ static ssize_t pblk_sysfs_lines(struct pblk *pblk, char *page) int free_line_cnt = 0, closed_line_cnt = 0, emeta_line_cnt = 0; int d_line_cnt = 0, l_line_cnt = 0; int gc_full = 0, gc_high = 0, gc_mid = 0, gc_low = 0, gc_empty = 0; + int gc_werr = 0; + int bad = 0, cor = 0; int msecs = 0, cur_sec = 0, vsc = 0, sec_in_line = 0; int map_weight = 0, meta_weight = 0; @@ -237,6 +239,15 @@ static ssize_t pblk_sysfs_lines(struct pblk *pblk, char *page) gc_empty++; } + list_for_each_entry(line, &l_mg->gc_werr_list, list) { + if (line->type == PBLK_LINETYPE_DATA) + d_line_cnt++; + else if (line->type == PBLK_LINETYPE_LOG) + l_line_cnt++; + closed_line_cnt++; + gc_werr++; + } + list_for_each_entry(line, &l_mg->bad_list, list) bad++; list_for_each_entry(line, &l_mg->corrupt_list, list) @@ -275,8 +286,8 @@ static ssize_t pblk_sysfs_lines(struct pblk *pblk, char *page) l_mg->nr_lines); sz += snprintf(page + sz, PAGE_SIZE - sz, - "GC: full:%d, high:%d, mid:%d, low:%d, empty:%d, queue:%d\n", - gc_full, gc_high, gc_mid, gc_low, gc_empty, + "GC: full:%d, high:%d, mid:%d, low:%d, empty:%d, werr: %d, queue:%d\n", + gc_full, gc_high, gc_mid, gc_low, gc_empty, gc_werr, atomic_read(&pblk->gc.read_inflight_gc)); sz += snprintf(page + sz, PAGE_SIZE - sz, diff --git a/drivers/lightnvm/pblk-write.c b/drivers/lightnvm/pblk-write.c index 3e6f1ebd743a..f353e52941f5 100644 --- a/drivers/lightnvm/pblk-write.c +++ b/drivers/lightnvm/pblk-write.c @@ -103,68 +103,150 @@ retry: pblk_rb_sync_end(&pblk->rwb, &flags); } -/* When a write fails, we are not sure whether the block has grown bad or a page - * range is more susceptible to write errors. If a high number of pages fail, we - * assume that the block is bad and we mark it accordingly. In all cases, we - * remap and resubmit the failed entries as fast as possible; if a flush is - * waiting on a completion, the whole stack would stall otherwise. - */ -static void pblk_end_w_fail(struct pblk *pblk, struct nvm_rq *rqd) +/* Map remaining sectors in chunk, starting from ppa */ +static void pblk_map_remaining(struct pblk *pblk, struct ppa_addr *ppa) { - void *comp_bits = &rqd->ppa_status; - struct pblk_c_ctx *c_ctx = nvm_rq_to_pdu(rqd); - struct pblk_rec_ctx *recovery; - struct ppa_addr *ppa_list = rqd->ppa_list; - int nr_ppas = rqd->nr_ppas; - unsigned int c_entries; - int bit, ret; + struct nvm_tgt_dev *dev = pblk->dev; + struct nvm_geo *geo = &dev->geo; + struct pblk_line *line; + struct ppa_addr map_ppa = *ppa; + u64 paddr; + int done = 0; - if (unlikely(nr_ppas == 1)) - ppa_list = &rqd->ppa_addr; + line = &pblk->lines[pblk_ppa_to_line(*ppa)]; + spin_lock(&line->lock); - recovery = mempool_alloc(pblk->rec_pool, GFP_ATOMIC); + while (!done) { + paddr = pblk_dev_ppa_to_line_addr(pblk, map_ppa); - INIT_LIST_HEAD(&recovery->failed); + if (!test_and_set_bit(paddr, line->map_bitmap)) + line->left_msecs--; - bit = -1; - while ((bit = find_next_bit(comp_bits, nr_ppas, bit + 1)) < nr_ppas) { - struct pblk_rb_entry *entry; - struct ppa_addr ppa; + if (!test_and_set_bit(paddr, line->invalid_bitmap)) + le32_add_cpu(line->vsc, -1); - /* Logic error */ - if (bit > c_ctx->nr_valid) { - WARN_ONCE(1, "pblk: corrupted write request\n"); - mempool_free(recovery, pblk->rec_pool); - goto out; + if (geo->version == NVM_OCSSD_SPEC_12) { + map_ppa.ppa++; + if (map_ppa.g.pg == geo->num_pg) + done = 1; + } else { + map_ppa.m.sec++; + if (map_ppa.m.sec == geo->clba) + done = 1; } + } - ppa = ppa_list[bit]; - entry = pblk_rb_sync_scan_entry(&pblk->rwb, &ppa); - if (!entry) { - pr_err("pblk: could not scan entry on write failure\n"); - mempool_free(recovery, pblk->rec_pool); - goto out; - } + line->w_err_gc->has_write_err = 1; + spin_unlock(&line->lock); +} - /* The list is filled first and emptied afterwards. No need for - * protecting it with a lock +static void pblk_prepare_resubmit(struct pblk *pblk, unsigned int sentry, + unsigned int nr_entries) +{ + struct pblk_rb *rb = &pblk->rwb; + struct pblk_rb_entry *entry; + struct pblk_line *line; + struct pblk_w_ctx *w_ctx; + struct ppa_addr ppa_l2p; + int flags; + unsigned int pos, i; + + spin_lock(&pblk->trans_lock); + pos = sentry; + for (i = 0; i < nr_entries; i++) { + entry = &rb->entries[pos]; + w_ctx = &entry->w_ctx; + + /* Check if the lba has been overwritten */ + ppa_l2p = pblk_trans_map_get(pblk, w_ctx->lba); + if (!pblk_ppa_comp(ppa_l2p, entry->cacheline)) + w_ctx->lba = ADDR_EMPTY; + + /* Mark up the entry as submittable again */ + flags = READ_ONCE(w_ctx->flags); + flags |= PBLK_WRITTEN_DATA; + /* Release flags on write context. Protect from writes */ + smp_store_release(&w_ctx->flags, flags); + + /* Decrese the reference count to the line as we will + * re-map these entries */ - list_add_tail(&entry->index, &recovery->failed); + line = &pblk->lines[pblk_ppa_to_line(w_ctx->ppa)]; + kref_put(&line->ref, pblk_line_put); + + pos = (pos + 1) & (rb->nr_entries - 1); } + spin_unlock(&pblk->trans_lock); +} - c_entries = find_first_bit(comp_bits, nr_ppas); - ret = pblk_recov_setup_rq(pblk, c_ctx, recovery, comp_bits, c_entries); - if (ret) { - pr_err("pblk: could not recover from write failure\n"); - mempool_free(recovery, pblk->rec_pool); - goto out; +static void pblk_queue_resubmit(struct pblk *pblk, struct pblk_c_ctx *c_ctx) +{ + struct pblk_c_ctx *r_ctx; + + r_ctx = kzalloc(sizeof(struct pblk_c_ctx), GFP_KERNEL); + if (!r_ctx) + return; + + r_ctx->lun_bitmap = NULL; + r_ctx->sentry = c_ctx->sentry; + r_ctx->nr_valid = c_ctx->nr_valid; + r_ctx->nr_padded = c_ctx->nr_padded; + + spin_lock(&pblk->resubmit_lock); + list_add_tail(&r_ctx->list, &pblk->resubmit_list); + spin_unlock(&pblk->resubmit_lock); + +#ifdef CONFIG_NVM_DEBUG + atomic_long_add(c_ctx->nr_valid, &pblk->recov_writes); +#endif +} + +static void pblk_submit_rec(struct work_struct *work) +{ + struct pblk_rec_ctx *recovery = + container_of(work, struct pblk_rec_ctx, ws_rec); + struct pblk *pblk = recovery->pblk; + struct nvm_rq *rqd = recovery->rqd; + struct pblk_c_ctx *c_ctx = nvm_rq_to_pdu(rqd); + struct ppa_addr *ppa_list; + + pblk_log_write_err(pblk, rqd); + + if (rqd->nr_ppas == 1) + ppa_list = &rqd->ppa_addr; + else + ppa_list = rqd->ppa_list; + + pblk_map_remaining(pblk, ppa_list); + pblk_queue_resubmit(pblk, c_ctx); + + pblk_up_rq(pblk, rqd->ppa_list, rqd->nr_ppas, c_ctx->lun_bitmap); + if (c_ctx->nr_padded) + pblk_bio_free_pages(pblk, rqd->bio, c_ctx->nr_valid, + c_ctx->nr_padded); + bio_put(rqd->bio); + pblk_free_rqd(pblk, rqd, PBLK_WRITE); + mempool_free(recovery, &pblk->rec_pool); + + atomic_dec(&pblk->inflight_io); +} + + +static void pblk_end_w_fail(struct pblk *pblk, struct nvm_rq *rqd) +{ + struct pblk_rec_ctx *recovery; + + recovery = mempool_alloc(&pblk->rec_pool, GFP_ATOMIC); + if (!recovery) { + pr_err("pblk: could not allocate recovery work\n"); + return; } + recovery->pblk = pblk; + recovery->rqd = rqd; + INIT_WORK(&recovery->ws_rec, pblk_submit_rec); queue_work(pblk->close_wq, &recovery->ws_rec); - -out: - pblk_complete_write(pblk, rqd, c_ctx); } static void pblk_end_io_write(struct nvm_rq *rqd) @@ -173,8 +255,8 @@ static void pblk_end_io_write(struct nvm_rq *rqd) struct pblk_c_ctx *c_ctx = nvm_rq_to_pdu(rqd); if (rqd->error) { - pblk_log_write_err(pblk, rqd); - return pblk_end_w_fail(pblk, rqd); + pblk_end_w_fail(pblk, rqd); + return; } #ifdef CONFIG_NVM_DEBUG else @@ -198,6 +280,7 @@ static void pblk_end_io_write_meta(struct nvm_rq *rqd) if (rqd->error) { pblk_log_write_err(pblk, rqd); pr_err("pblk: metadata I/O failed. Line %d\n", line->id); + line->w_err_gc->has_write_err = 1; } sync = atomic_add_return(rqd->nr_ppas, &emeta->sync); @@ -266,31 +349,6 @@ static int pblk_setup_w_rq(struct pblk *pblk, struct nvm_rq *rqd, return 0; } -int pblk_setup_w_rec_rq(struct pblk *pblk, struct nvm_rq *rqd, - struct pblk_c_ctx *c_ctx) -{ - struct pblk_line_meta *lm = &pblk->lm; - unsigned long *lun_bitmap; - int ret; - - lun_bitmap = kzalloc(lm->lun_bitmap_len, GFP_KERNEL); - if (!lun_bitmap) - return -ENOMEM; - - c_ctx->lun_bitmap = lun_bitmap; - - ret = pblk_alloc_w_rq(pblk, rqd, rqd->nr_ppas, pblk_end_io_write); - if (ret) - return ret; - - pblk_map_rq(pblk, rqd, c_ctx->sentry, lun_bitmap, c_ctx->nr_valid, 0); - - rqd->ppa_status = (u64)0; - rqd->flags = pblk_set_progr_mode(pblk, PBLK_WRITE); - - return ret; -} - static int pblk_calc_secs_to_sync(struct pblk *pblk, unsigned int secs_avail, unsigned int secs_to_flush) { @@ -339,6 +397,7 @@ int pblk_submit_meta_io(struct pblk *pblk, struct pblk_line *meta_line) bio = pblk_bio_map_addr(pblk, data, rq_ppas, rq_len, l_mg->emeta_alloc_type, GFP_KERNEL); if (IS_ERR(bio)) { + pr_err("pblk: failed to map emeta io"); ret = PTR_ERR(bio); goto fail_free_rqd; } @@ -515,26 +574,54 @@ static int pblk_submit_write(struct pblk *pblk) unsigned int secs_avail, secs_to_sync, secs_to_com; unsigned int secs_to_flush; unsigned long pos; + unsigned int resubmit; - /* If there are no sectors in the cache, flushes (bios without data) - * will be cleared on the cache threads - */ - secs_avail = pblk_rb_read_count(&pblk->rwb); - if (!secs_avail) - return 1; - - secs_to_flush = pblk_rb_flush_point_count(&pblk->rwb); - if (!secs_to_flush && secs_avail < pblk->min_write_pgs) - return 1; - - secs_to_sync = pblk_calc_secs_to_sync(pblk, secs_avail, secs_to_flush); - if (secs_to_sync > pblk->max_write_pgs) { - pr_err("pblk: bad buffer sync calculation\n"); - return 1; - } + spin_lock(&pblk->resubmit_lock); + resubmit = !list_empty(&pblk->resubmit_list); + spin_unlock(&pblk->resubmit_lock); + + /* Resubmit failed writes first */ + if (resubmit) { + struct pblk_c_ctx *r_ctx; + + spin_lock(&pblk->resubmit_lock); + r_ctx = list_first_entry(&pblk->resubmit_list, + struct pblk_c_ctx, list); + list_del(&r_ctx->list); + spin_unlock(&pblk->resubmit_lock); + + secs_avail = r_ctx->nr_valid; + pos = r_ctx->sentry; + + pblk_prepare_resubmit(pblk, pos, secs_avail); + secs_to_sync = pblk_calc_secs_to_sync(pblk, secs_avail, + secs_avail); - secs_to_com = (secs_to_sync > secs_avail) ? secs_avail : secs_to_sync; - pos = pblk_rb_read_commit(&pblk->rwb, secs_to_com); + kfree(r_ctx); + } else { + /* If there are no sectors in the cache, + * flushes (bios without data) will be cleared on + * the cache threads + */ + secs_avail = pblk_rb_read_count(&pblk->rwb); + if (!secs_avail) + return 1; + + secs_to_flush = pblk_rb_flush_point_count(&pblk->rwb); + if (!secs_to_flush && secs_avail < pblk->min_write_pgs) + return 1; + + secs_to_sync = pblk_calc_secs_to_sync(pblk, secs_avail, + secs_to_flush); + if (secs_to_sync > pblk->max_write_pgs) { + pr_err("pblk: bad buffer sync calculation\n"); + return 1; + } + + secs_to_com = (secs_to_sync > secs_avail) ? + secs_avail : secs_to_sync; + pos = pblk_rb_read_commit(&pblk->rwb, secs_to_com); + } bio = bio_alloc(GFP_KERNEL, secs_to_sync); diff --git a/drivers/lightnvm/pblk.h b/drivers/lightnvm/pblk.h index 9c682acfc5d1..34cc1d64a9d4 100644 --- a/drivers/lightnvm/pblk.h +++ b/drivers/lightnvm/pblk.h @@ -89,12 +89,14 @@ struct pblk_sec_meta { /* The number of GC lists and the rate-limiter states go together. This way the * rate-limiter can dictate how much GC is needed based on resource utilization. */ -#define PBLK_GC_NR_LISTS 3 +#define PBLK_GC_NR_LISTS 4 enum { - PBLK_RL_HIGH = 1, - PBLK_RL_MID = 2, - PBLK_RL_LOW = 3, + PBLK_RL_OFF = 0, + PBLK_RL_WERR = 1, + PBLK_RL_HIGH = 2, + PBLK_RL_MID = 3, + PBLK_RL_LOW = 4 }; #define pblk_dma_meta_size (sizeof(struct pblk_sec_meta) * PBLK_MAX_REQ_ADDRS) @@ -128,7 +130,6 @@ struct pblk_pad_rq { struct pblk_rec_ctx { struct pblk *pblk; struct nvm_rq *rqd; - struct list_head failed; struct work_struct ws_rec; }; @@ -279,6 +280,8 @@ struct pblk_rl { int rb_user_active; int rb_gc_active; + atomic_t werr_lines; /* Number of write error lines that needs gc */ + struct timer_list u_timer; unsigned long long nr_secs; @@ -312,6 +315,7 @@ enum { PBLK_LINEGC_MID = 23, PBLK_LINEGC_HIGH = 24, PBLK_LINEGC_FULL = 25, + PBLK_LINEGC_WERR = 26 }; #define PBLK_MAGIC 0x70626c6b /*pblk*/ @@ -413,6 +417,11 @@ struct pblk_smeta { struct line_smeta *buf; /* smeta buffer in persistent format */ }; +struct pblk_w_err_gc { + int has_write_err; + __le64 *lba_list; +}; + struct pblk_line { struct pblk *pblk; unsigned int id; /* Line number corresponds to the @@ -458,6 +467,8 @@ struct pblk_line { struct kref ref; /* Write buffer L2P references */ + struct pblk_w_err_gc *w_err_gc; /* Write error gc recovery metadata */ + spinlock_t lock; /* Necessary for invalid_bitmap only */ }; @@ -489,6 +500,8 @@ struct pblk_line_mgmt { struct list_head gc_mid_list; /* Full lines ready to GC, mid isc */ struct list_head gc_low_list; /* Full lines ready to GC, low isc */ + struct list_head gc_werr_list; /* Write err recovery list */ + struct list_head gc_full_list; /* Full lines ready to GC, no valid */ struct list_head gc_empty_list; /* Full lines close, all valid */ @@ -664,12 +677,15 @@ struct pblk { struct list_head compl_list; - mempool_t *page_bio_pool; - mempool_t *gen_ws_pool; - mempool_t *rec_pool; - mempool_t *r_rq_pool; - mempool_t *w_rq_pool; - mempool_t *e_rq_pool; + spinlock_t resubmit_lock; /* Resubmit list lock */ + struct list_head resubmit_list; /* Resubmit list for failed writes*/ + + mempool_t page_bio_pool; + mempool_t gen_ws_pool; + mempool_t rec_pool; + mempool_t r_rq_pool; + mempool_t w_rq_pool; + mempool_t e_rq_pool; struct workqueue_struct *close_wq; struct workqueue_struct *bb_wq; @@ -713,9 +729,6 @@ void pblk_rb_sync_l2p(struct pblk_rb *rb); unsigned int pblk_rb_read_to_bio(struct pblk_rb *rb, struct nvm_rq *rqd, unsigned int pos, unsigned int nr_entries, unsigned int count); -unsigned int pblk_rb_read_to_bio_list(struct pblk_rb *rb, struct bio *bio, - struct list_head *list, - unsigned int max); int pblk_rb_copy_to_bio(struct pblk_rb *rb, struct bio *bio, sector_t lba, struct ppa_addr ppa, int bio_iter, bool advanced_bio); unsigned int pblk_rb_read_commit(struct pblk_rb *rb, unsigned int entries); @@ -766,11 +779,13 @@ struct pblk_line *pblk_line_get_data(struct pblk *pblk); struct pblk_line *pblk_line_get_erase(struct pblk *pblk); int pblk_line_erase(struct pblk *pblk, struct pblk_line *line); int pblk_line_is_full(struct pblk_line *line); -void pblk_line_free(struct pblk *pblk, struct pblk_line *line); +void pblk_line_free(struct pblk_line *line); void pblk_line_close_meta(struct pblk *pblk, struct pblk_line *line); void pblk_line_close(struct pblk *pblk, struct pblk_line *line); void pblk_line_close_ws(struct work_struct *work); void pblk_pipeline_stop(struct pblk *pblk); +void __pblk_pipeline_stop(struct pblk *pblk); +void __pblk_pipeline_flush(struct pblk *pblk); void pblk_gen_run_ws(struct pblk *pblk, struct pblk_line *line, void *priv, void (*work)(struct work_struct *), gfp_t gfp_mask, struct workqueue_struct *wq); @@ -794,7 +809,6 @@ void pblk_down_rq(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas, void pblk_down_page(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas); void pblk_up_rq(struct pblk *pblk, struct ppa_addr *ppa_list, int nr_ppas, unsigned long *lun_bitmap); -void pblk_end_io_sync(struct nvm_rq *rqd); int pblk_bio_add_pages(struct pblk *pblk, struct bio *bio, gfp_t flags, int nr_pages); void pblk_bio_free_pages(struct pblk *pblk, struct bio *bio, int off, @@ -837,23 +851,20 @@ void pblk_map_rq(struct pblk *pblk, struct nvm_rq *rqd, unsigned int sentry, int pblk_write_ts(void *data); void pblk_write_timer_fn(struct timer_list *t); void pblk_write_should_kick(struct pblk *pblk); +void pblk_write_kick(struct pblk *pblk); /* * pblk read path */ -extern struct bio_set *pblk_bio_set; +extern struct bio_set pblk_bio_set; int pblk_submit_read(struct pblk *pblk, struct bio *bio); int pblk_submit_read_gc(struct pblk *pblk, struct pblk_gc_rq *gc_rq); /* * pblk recovery */ -void pblk_submit_rec(struct work_struct *work); struct pblk_line *pblk_recov_l2p(struct pblk *pblk); int pblk_recov_pad(struct pblk *pblk); int pblk_recov_check_emeta(struct pblk *pblk, struct line_emeta *emeta); -int pblk_recov_setup_rq(struct pblk *pblk, struct pblk_c_ctx *c_ctx, - struct pblk_rec_ctx *recovery, u64 *comp_bits, - unsigned int comp); /* * pblk gc @@ -864,7 +875,7 @@ int pblk_recov_setup_rq(struct pblk *pblk, struct pblk_c_ctx *c_ctx, #define PBLK_GC_RSV_LINE 1 /* Reserved lines for GC */ int pblk_gc_init(struct pblk *pblk); -void pblk_gc_exit(struct pblk *pblk); +void pblk_gc_exit(struct pblk *pblk, bool graceful); void pblk_gc_should_start(struct pblk *pblk); void pblk_gc_should_stop(struct pblk *pblk); void pblk_gc_should_kick(struct pblk *pblk); @@ -894,6 +905,9 @@ void pblk_rl_free_lines_dec(struct pblk_rl *rl, struct pblk_line *line, bool used); int pblk_rl_is_limit(struct pblk_rl *rl); +void pblk_rl_werr_line_in(struct pblk_rl *rl); +void pblk_rl_werr_line_out(struct pblk_rl *rl); + /* * pblk sysfs */ diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 433dbeddfcf9..6663893f41c4 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -191,10 +191,10 @@ static int init_pmu(void); static void pmu_start(void); static irqreturn_t via_pmu_interrupt(int irq, void *arg); static irqreturn_t gpio1_interrupt(int irq, void *arg); -static const struct file_operations pmu_info_proc_fops; -static const struct file_operations pmu_irqstats_proc_fops; +static int pmu_info_proc_show(struct seq_file *m, void *v); +static int pmu_irqstats_proc_show(struct seq_file *m, void *v); +static int pmu_battery_proc_show(struct seq_file *m, void *v); static void pmu_pass_intr(unsigned char *data, int len); -static const struct file_operations pmu_battery_proc_fops; static const struct file_operations pmu_options_proc_fops; #ifdef CONFIG_ADB @@ -511,13 +511,15 @@ static int __init via_pmu_dev_init(void) for (i=0; i<pmu_battery_count; i++) { char title[16]; sprintf(title, "battery_%ld", i); - proc_pmu_batt[i] = proc_create_data(title, 0, proc_pmu_root, - &pmu_battery_proc_fops, (void *)i); + proc_pmu_batt[i] = proc_create_single_data(title, 0, + proc_pmu_root, pmu_battery_proc_show, + (void *)i); } - proc_pmu_info = proc_create("info", 0, proc_pmu_root, &pmu_info_proc_fops); - proc_pmu_irqstats = proc_create("interrupts", 0, proc_pmu_root, - &pmu_irqstats_proc_fops); + proc_pmu_info = proc_create_single("info", 0, proc_pmu_root, + pmu_info_proc_show); + proc_pmu_irqstats = proc_create_single("interrupts", 0, + proc_pmu_root, pmu_irqstats_proc_show); proc_pmu_options = proc_create("options", 0600, proc_pmu_root, &pmu_options_proc_fops); } @@ -811,19 +813,6 @@ static int pmu_info_proc_show(struct seq_file *m, void *v) return 0; } -static int pmu_info_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, pmu_info_proc_show, NULL); -} - -static const struct file_operations pmu_info_proc_fops = { - .owner = THIS_MODULE, - .open = pmu_info_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static int pmu_irqstats_proc_show(struct seq_file *m, void *v) { int i; @@ -848,19 +837,6 @@ static int pmu_irqstats_proc_show(struct seq_file *m, void *v) return 0; } -static int pmu_irqstats_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, pmu_irqstats_proc_show, NULL); -} - -static const struct file_operations pmu_irqstats_proc_fops = { - .owner = THIS_MODULE, - .open = pmu_irqstats_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static int pmu_battery_proc_show(struct seq_file *m, void *v) { long batnum = (long)m->private; @@ -875,19 +851,6 @@ static int pmu_battery_proc_show(struct seq_file *m, void *v) return 0; } -static int pmu_battery_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, pmu_battery_proc_show, PDE_DATA(inode)); -} - -static const struct file_operations pmu_battery_proc_fops = { - .owner = THIS_MODULE, - .open = pmu_battery_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static int pmu_options_proc_show(struct seq_file *m, void *v) { #if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32) diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c index 3ef7f036ceea..fc3c237daef2 100644 --- a/drivers/mailbox/pcc.c +++ b/drivers/mailbox/pcc.c @@ -373,33 +373,24 @@ static const struct mbox_chan_ops pcc_chan_ops = { }; /** - * parse_pcc_subspace - Parse the PCC table and verify PCC subspace - * entries. There should be one entry per PCC client. + * parse_pcc_subspaces -- Count PCC subspaces defined * @header: Pointer to the ACPI subtable header under the PCCT. * @end: End of subtable entry. * - * Return: 0 for Success, else errno. + * Return: If we find a PCC subspace entry of a valid type, return 0. + * Otherwise, return -EINVAL. * * This gets called for each entry in the PCC table. */ static int parse_pcc_subspace(struct acpi_subtable_header *header, const unsigned long end) { - struct acpi_pcct_hw_reduced *pcct_ss; - - if (pcc_mbox_ctrl.num_chans <= MAX_PCC_SUBSPACES) { - pcct_ss = (struct acpi_pcct_hw_reduced *) header; + struct acpi_pcct_subspace *ss = (struct acpi_pcct_subspace *) header; - if ((pcct_ss->header.type != - ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE) - && (pcct_ss->header.type != - ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE_TYPE2)) { - pr_err("Incorrect PCC Subspace type detected\n"); - return -EINVAL; - } - } + if (ss->header.type < ACPI_PCCT_TYPE_RESERVED) + return 0; - return 0; + return -EINVAL; } /** @@ -449,8 +440,8 @@ static int __init acpi_pcc_probe(void) struct acpi_table_header *pcct_tbl; struct acpi_subtable_header *pcct_entry; struct acpi_table_pcct *acpi_pcct_tbl; + struct acpi_subtable_proc proc[ACPI_PCCT_TYPE_RESERVED]; int count, i, rc; - int sum = 0; acpi_status status = AE_OK; /* Search for PCCT */ @@ -459,43 +450,41 @@ static int __init acpi_pcc_probe(void) if (ACPI_FAILURE(status) || !pcct_tbl) return -ENODEV; - count = acpi_table_parse_entries(ACPI_SIG_PCCT, - sizeof(struct acpi_table_pcct), - ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE, - parse_pcc_subspace, MAX_PCC_SUBSPACES); - sum += (count > 0) ? count : 0; - - count = acpi_table_parse_entries(ACPI_SIG_PCCT, - sizeof(struct acpi_table_pcct), - ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE_TYPE2, - parse_pcc_subspace, MAX_PCC_SUBSPACES); - sum += (count > 0) ? count : 0; + /* Set up the subtable handlers */ + for (i = ACPI_PCCT_TYPE_GENERIC_SUBSPACE; + i < ACPI_PCCT_TYPE_RESERVED; i++) { + proc[i].id = i; + proc[i].count = 0; + proc[i].handler = parse_pcc_subspace; + } - if (sum == 0 || sum >= MAX_PCC_SUBSPACES) { - pr_err("Error parsing PCC subspaces from PCCT\n"); + count = acpi_table_parse_entries_array(ACPI_SIG_PCCT, + sizeof(struct acpi_table_pcct), proc, + ACPI_PCCT_TYPE_RESERVED, MAX_PCC_SUBSPACES); + if (count == 0 || count > MAX_PCC_SUBSPACES) { + pr_warn("Invalid PCCT: %d PCC subspaces\n", count); return -EINVAL; } - pcc_mbox_channels = kzalloc(sizeof(struct mbox_chan) * - sum, GFP_KERNEL); + pcc_mbox_channels = kzalloc(sizeof(struct mbox_chan) * count, GFP_KERNEL); if (!pcc_mbox_channels) { pr_err("Could not allocate space for PCC mbox channels\n"); return -ENOMEM; } - pcc_doorbell_vaddr = kcalloc(sum, sizeof(void *), GFP_KERNEL); + pcc_doorbell_vaddr = kcalloc(count, sizeof(void *), GFP_KERNEL); if (!pcc_doorbell_vaddr) { rc = -ENOMEM; goto err_free_mbox; } - pcc_doorbell_ack_vaddr = kcalloc(sum, sizeof(void *), GFP_KERNEL); + pcc_doorbell_ack_vaddr = kcalloc(count, sizeof(void *), GFP_KERNEL); if (!pcc_doorbell_ack_vaddr) { rc = -ENOMEM; goto err_free_db_vaddr; } - pcc_doorbell_irq = kcalloc(sum, sizeof(int), GFP_KERNEL); + pcc_doorbell_irq = kcalloc(count, sizeof(int), GFP_KERNEL); if (!pcc_doorbell_irq) { rc = -ENOMEM; goto err_free_db_ack_vaddr; @@ -509,18 +498,24 @@ static int __init acpi_pcc_probe(void) if (acpi_pcct_tbl->flags & ACPI_PCCT_DOORBELL) pcc_mbox_ctrl.txdone_irq = true; - for (i = 0; i < sum; i++) { + for (i = 0; i < count; i++) { struct acpi_generic_address *db_reg; - struct acpi_pcct_hw_reduced *pcct_ss; + struct acpi_pcct_subspace *pcct_ss; pcc_mbox_channels[i].con_priv = pcct_entry; - pcct_ss = (struct acpi_pcct_hw_reduced *) pcct_entry; + if (pcct_entry->type == ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE || + pcct_entry->type == ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE_TYPE2) { + struct acpi_pcct_hw_reduced *pcct_hrss; + + pcct_hrss = (struct acpi_pcct_hw_reduced *) pcct_entry; - if (pcc_mbox_ctrl.txdone_irq) { - rc = pcc_parse_subspace_irq(i, pcct_ss); - if (rc < 0) - goto err; + if (pcc_mbox_ctrl.txdone_irq) { + rc = pcc_parse_subspace_irq(i, pcct_hrss); + if (rc < 0) + goto err; + } } + pcct_ss = (struct acpi_pcct_subspace *) pcct_entry; /* If doorbell is in system memory cache the virt address */ db_reg = &pcct_ss->doorbell_register; @@ -531,7 +526,7 @@ static int __init acpi_pcc_probe(void) ((unsigned long) pcct_entry + pcct_entry->length); } - pcc_mbox_ctrl.num_chans = sum; + pcc_mbox_ctrl.num_chans = count; pr_info("Detected %d PCC Subspaces\n", pcc_mbox_ctrl.num_chans); diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h index 3a0cfb237af9..d6bf294f3907 100644 --- a/drivers/md/bcache/bcache.h +++ b/drivers/md/bcache/bcache.h @@ -269,7 +269,7 @@ struct bcache_device { atomic_t *stripe_sectors_dirty; unsigned long *full_dirty_stripes; - struct bio_set *bio_split; + struct bio_set bio_split; unsigned data_csum:1; @@ -345,6 +345,7 @@ struct cached_dev { struct keybuf writeback_keys; + struct task_struct *status_update_thread; /* * Order the write-half of writeback operations strongly in dispatch * order. (Maintain LBA order; don't allow reads completing out of @@ -392,6 +393,7 @@ struct cached_dev { #define DEFAULT_CACHED_DEV_ERROR_LIMIT 64 atomic_t io_errors; unsigned error_limit; + unsigned offline_seconds; char backing_dev_name[BDEVNAME_SIZE]; }; @@ -528,9 +530,9 @@ struct cache_set { struct closure sb_write; struct semaphore sb_write_mutex; - mempool_t *search; - mempool_t *bio_meta; - struct bio_set *bio_split; + mempool_t search; + mempool_t bio_meta; + struct bio_set bio_split; /* For the btree cache */ struct shrinker shrink; @@ -655,7 +657,7 @@ struct cache_set { * A btree node on disk could have too many bsets for an iterator to fit * on the stack - have to dynamically allocate them */ - mempool_t *fill_iter; + mempool_t fill_iter; struct bset_sort_state sort; @@ -956,8 +958,6 @@ void bch_prio_write(struct cache *); void bch_write_bdev_super(struct cached_dev *, struct closure *); extern struct workqueue_struct *bcache_wq; -extern const char * const bch_cache_modes[]; -extern const char * const bch_stop_on_failure_modes[]; extern struct mutex bch_register_lock; extern struct list_head bch_cache_sets; diff --git a/drivers/md/bcache/bset.c b/drivers/md/bcache/bset.c index 579c696a5fe0..f3403b45bc28 100644 --- a/drivers/md/bcache/bset.c +++ b/drivers/md/bcache/bset.c @@ -1118,8 +1118,7 @@ struct bkey *bch_btree_iter_next_filter(struct btree_iter *iter, void bch_bset_sort_state_free(struct bset_sort_state *state) { - if (state->pool) - mempool_destroy(state->pool); + mempool_exit(&state->pool); } int bch_bset_sort_state_init(struct bset_sort_state *state, unsigned page_order) @@ -1129,11 +1128,7 @@ int bch_bset_sort_state_init(struct bset_sort_state *state, unsigned page_order) state->page_order = page_order; state->crit_factor = int_sqrt(1 << page_order); - state->pool = mempool_create_page_pool(1, page_order); - if (!state->pool) - return -ENOMEM; - - return 0; + return mempool_init_page_pool(&state->pool, 1, page_order); } EXPORT_SYMBOL(bch_bset_sort_state_init); @@ -1191,7 +1186,7 @@ static void __btree_sort(struct btree_keys *b, struct btree_iter *iter, BUG_ON(order > state->page_order); - outp = mempool_alloc(state->pool, GFP_NOIO); + outp = mempool_alloc(&state->pool, GFP_NOIO); out = page_address(outp); used_mempool = true; order = state->page_order; @@ -1220,7 +1215,7 @@ static void __btree_sort(struct btree_keys *b, struct btree_iter *iter, } if (used_mempool) - mempool_free(virt_to_page(out), state->pool); + mempool_free(virt_to_page(out), &state->pool); else free_pages((unsigned long) out, order); diff --git a/drivers/md/bcache/bset.h b/drivers/md/bcache/bset.h index 0c24280f3b98..b867f2200495 100644 --- a/drivers/md/bcache/bset.h +++ b/drivers/md/bcache/bset.h @@ -347,7 +347,7 @@ static inline struct bkey *bch_bset_search(struct btree_keys *b, /* Sorting */ struct bset_sort_state { - mempool_t *pool; + mempool_t pool; unsigned page_order; unsigned crit_factor; diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c index 17936b2dc7d6..2a0968c04e21 100644 --- a/drivers/md/bcache/btree.c +++ b/drivers/md/bcache/btree.c @@ -204,7 +204,7 @@ void bch_btree_node_read_done(struct btree *b) struct bset *i = btree_bset_first(b); struct btree_iter *iter; - iter = mempool_alloc(b->c->fill_iter, GFP_NOIO); + iter = mempool_alloc(&b->c->fill_iter, GFP_NOIO); iter->size = b->c->sb.bucket_size / b->c->sb.block_size; iter->used = 0; @@ -271,7 +271,7 @@ void bch_btree_node_read_done(struct btree *b) bch_bset_init_next(&b->keys, write_block(b), bset_magic(&b->c->sb)); out: - mempool_free(iter, b->c->fill_iter); + mempool_free(iter, &b->c->fill_iter); return; err: set_btree_node_io_error(b); diff --git a/drivers/md/bcache/io.c b/drivers/md/bcache/io.c index 2ddf8515e6a5..9612873afee2 100644 --- a/drivers/md/bcache/io.c +++ b/drivers/md/bcache/io.c @@ -17,12 +17,12 @@ void bch_bbio_free(struct bio *bio, struct cache_set *c) { struct bbio *b = container_of(bio, struct bbio, bio); - mempool_free(b, c->bio_meta); + mempool_free(b, &c->bio_meta); } struct bio *bch_bbio_alloc(struct cache_set *c) { - struct bbio *b = mempool_alloc(c->bio_meta, GFP_NOIO); + struct bbio *b = mempool_alloc(&c->bio_meta, GFP_NOIO); struct bio *bio = &b->bio; bio_init(bio, bio->bi_inline_vecs, bucket_pages(c)); diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c index 8e3e8655ed63..ae67f5fa8047 100644 --- a/drivers/md/bcache/request.c +++ b/drivers/md/bcache/request.c @@ -213,7 +213,7 @@ static void bch_data_insert_start(struct closure *cl) do { unsigned i; struct bkey *k; - struct bio_set *split = op->c->bio_split; + struct bio_set *split = &op->c->bio_split; /* 1 for the device pointer and 1 for the chksum */ if (bch_keylist_realloc(&op->insert_keys, @@ -548,7 +548,7 @@ static int cache_lookup_fn(struct btree_op *op, struct btree *b, struct bkey *k) n = bio_next_split(bio, min_t(uint64_t, INT_MAX, KEY_OFFSET(k) - bio->bi_iter.bi_sector), - GFP_NOIO, s->d->bio_split); + GFP_NOIO, &s->d->bio_split); bio_key = &container_of(n, struct bbio, bio)->key; bch_bkey_copy_single_ptr(bio_key, k, ptr); @@ -707,7 +707,7 @@ static void search_free(struct closure *cl) bio_complete(s); closure_debug_destroy(cl); - mempool_free(s, s->d->c->search); + mempool_free(s, &s->d->c->search); } static inline struct search *search_alloc(struct bio *bio, @@ -715,7 +715,7 @@ static inline struct search *search_alloc(struct bio *bio, { struct search *s; - s = mempool_alloc(d->c->search, GFP_NOIO); + s = mempool_alloc(&d->c->search, GFP_NOIO); closure_init(&s->cl, NULL); do_bio_hook(s, bio, request_endio); @@ -864,7 +864,7 @@ static int cached_dev_cache_miss(struct btree *b, struct search *s, s->cache_missed = 1; if (s->cache_miss || s->iop.bypass) { - miss = bio_next_split(bio, sectors, GFP_NOIO, s->d->bio_split); + miss = bio_next_split(bio, sectors, GFP_NOIO, &s->d->bio_split); ret = miss == bio ? MAP_DONE : MAP_CONTINUE; goto out_submit; } @@ -887,14 +887,14 @@ static int cached_dev_cache_miss(struct btree *b, struct search *s, s->iop.replace = true; - miss = bio_next_split(bio, sectors, GFP_NOIO, s->d->bio_split); + miss = bio_next_split(bio, sectors, GFP_NOIO, &s->d->bio_split); /* btree_search_recurse()'s btree iterator is no good anymore */ ret = miss == bio ? MAP_DONE : -EINTR; cache_bio = bio_alloc_bioset(GFP_NOWAIT, DIV_ROUND_UP(s->insert_bio_sectors, PAGE_SECTORS), - dc->disk.bio_split); + &dc->disk.bio_split); if (!cache_bio) goto out_submit; @@ -1008,7 +1008,7 @@ static void cached_dev_write(struct cached_dev *dc, struct search *s) struct bio *flush; flush = bio_alloc_bioset(GFP_NOIO, 0, - dc->disk.bio_split); + &dc->disk.bio_split); if (!flush) { s->iop.status = BLK_STS_RESOURCE; goto insert_data; @@ -1021,7 +1021,7 @@ static void cached_dev_write(struct cached_dev *dc, struct search *s) closure_bio_submit(s->iop.c, flush, cl); } } else { - s->iop.bio = bio_clone_fast(bio, GFP_NOIO, dc->disk.bio_split); + s->iop.bio = bio_clone_fast(bio, GFP_NOIO, &dc->disk.bio_split); /* I/O request sent to backing device */ bio->bi_end_io = backing_request_endio; closure_bio_submit(s->iop.c, bio, cl); diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index 3dea06b41d43..a31e55bcc4e5 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -37,24 +37,6 @@ static const char invalid_uuid[] = { 0xc8, 0x50, 0xfc, 0x5e, 0xcb, 0x16, 0xcd, 0x99 }; -/* Default is -1; we skip past it for struct cached_dev's cache mode */ -const char * const bch_cache_modes[] = { - "default", - "writethrough", - "writeback", - "writearound", - "none", - NULL -}; - -/* Default is -1; we skip past it for stop_when_cache_set_failed */ -const char * const bch_stop_on_failure_modes[] = { - "default", - "auto", - "always", - NULL -}; - static struct kobject *bcache_kobj; struct mutex bch_register_lock; LIST_HEAD(bch_cache_sets); @@ -654,6 +636,11 @@ static int ioctl_dev(struct block_device *b, fmode_t mode, unsigned int cmd, unsigned long arg) { struct bcache_device *d = b->bd_disk->private_data; + struct cached_dev *dc = container_of(d, struct cached_dev, disk); + + if (dc->io_disable) + return -EIO; + return d->ioctl(d, mode, cmd, arg); } @@ -766,8 +753,7 @@ static void bcache_device_free(struct bcache_device *d) put_disk(d->disk); } - if (d->bio_split) - bioset_free(d->bio_split); + bioset_exit(&d->bio_split); kvfree(d->full_dirty_stripes); kvfree(d->stripe_sectors_dirty); @@ -809,9 +795,8 @@ static int bcache_device_init(struct bcache_device *d, unsigned block_size, if (idx < 0) return idx; - if (!(d->bio_split = bioset_create(4, offsetof(struct bbio, bio), - BIOSET_NEED_BVECS | - BIOSET_NEED_RESCUER)) || + if (bioset_init(&d->bio_split, 4, offsetof(struct bbio, bio), + BIOSET_NEED_BVECS|BIOSET_NEED_RESCUER) || !(d->disk = alloc_disk(BCACHE_MINORS))) { ida_simple_remove(&bcache_device_idx, idx); return -ENOMEM; @@ -864,6 +849,44 @@ static void calc_cached_dev_sectors(struct cache_set *c) c->cached_dev_sectors = sectors; } +#define BACKING_DEV_OFFLINE_TIMEOUT 5 +static int cached_dev_status_update(void *arg) +{ + struct cached_dev *dc = arg; + struct request_queue *q; + + /* + * If this delayed worker is stopping outside, directly quit here. + * dc->io_disable might be set via sysfs interface, so check it + * here too. + */ + while (!kthread_should_stop() && !dc->io_disable) { + q = bdev_get_queue(dc->bdev); + if (blk_queue_dying(q)) + dc->offline_seconds++; + else + dc->offline_seconds = 0; + + if (dc->offline_seconds >= BACKING_DEV_OFFLINE_TIMEOUT) { + pr_err("%s: device offline for %d seconds", + dc->backing_dev_name, + BACKING_DEV_OFFLINE_TIMEOUT); + pr_err("%s: disable I/O request due to backing " + "device offline", dc->disk.name); + dc->io_disable = true; + /* let others know earlier that io_disable is true */ + smp_mb(); + bcache_device_stop(&dc->disk); + break; + } + schedule_timeout_interruptible(HZ); + } + + wait_for_kthread_stop(); + return 0; +} + + void bch_cached_dev_run(struct cached_dev *dc) { struct bcache_device *d = &dc->disk; @@ -906,6 +929,14 @@ void bch_cached_dev_run(struct cached_dev *dc) if (sysfs_create_link(&d->kobj, &disk_to_dev(d->disk)->kobj, "dev") || sysfs_create_link(&disk_to_dev(d->disk)->kobj, &d->kobj, "bcache")) pr_debug("error creating sysfs link"); + + dc->status_update_thread = kthread_run(cached_dev_status_update, + dc, "bcache_status_update"); + if (IS_ERR(dc->status_update_thread)) { + pr_warn("failed to create bcache_status_update kthread, " + "continue to run without monitoring backing " + "device status"); + } } /* @@ -1139,6 +1170,8 @@ static void cached_dev_free(struct closure *cl) kthread_stop(dc->writeback_thread); if (dc->writeback_write_wq) destroy_workqueue(dc->writeback_write_wq); + if (!IS_ERR_OR_NULL(dc->status_update_thread)) + kthread_stop(dc->status_update_thread); if (atomic_read(&dc->running)) bd_unlink_disk_holder(dc->bdev, dc->disk.disk); @@ -1465,14 +1498,10 @@ static void cache_set_free(struct closure *cl) if (c->moving_gc_wq) destroy_workqueue(c->moving_gc_wq); - if (c->bio_split) - bioset_free(c->bio_split); - if (c->fill_iter) - mempool_destroy(c->fill_iter); - if (c->bio_meta) - mempool_destroy(c->bio_meta); - if (c->search) - mempool_destroy(c->search); + bioset_exit(&c->bio_split); + mempool_exit(&c->fill_iter); + mempool_exit(&c->bio_meta); + mempool_exit(&c->search); kfree(c->devices); mutex_lock(&bch_register_lock); @@ -1683,21 +1712,17 @@ struct cache_set *bch_cache_set_alloc(struct cache_sb *sb) INIT_LIST_HEAD(&c->btree_cache_freed); INIT_LIST_HEAD(&c->data_buckets); - c->search = mempool_create_slab_pool(32, bch_search_cache); - if (!c->search) - goto err; - iter_size = (sb->bucket_size / sb->block_size + 1) * sizeof(struct btree_iter_set); if (!(c->devices = kzalloc(c->nr_uuids * sizeof(void *), GFP_KERNEL)) || - !(c->bio_meta = mempool_create_kmalloc_pool(2, - sizeof(struct bbio) + sizeof(struct bio_vec) * - bucket_pages(c))) || - !(c->fill_iter = mempool_create_kmalloc_pool(1, iter_size)) || - !(c->bio_split = bioset_create(4, offsetof(struct bbio, bio), - BIOSET_NEED_BVECS | - BIOSET_NEED_RESCUER)) || + mempool_init_slab_pool(&c->search, 32, bch_search_cache) || + mempool_init_kmalloc_pool(&c->bio_meta, 2, + sizeof(struct bbio) + sizeof(struct bio_vec) * + bucket_pages(c)) || + mempool_init_kmalloc_pool(&c->fill_iter, 1, iter_size) || + bioset_init(&c->bio_split, 4, offsetof(struct bbio, bio), + BIOSET_NEED_BVECS|BIOSET_NEED_RESCUER) || !(c->uuids = alloc_bucket_pages(GFP_KERNEL, c)) || !(c->moving_gc_wq = alloc_workqueue("bcache_gc", WQ_MEM_RECLAIM, 0)) || diff --git a/drivers/md/bcache/sysfs.c b/drivers/md/bcache/sysfs.c index dfeef583ee50..8ccbc8f3b3af 100644 --- a/drivers/md/bcache/sysfs.c +++ b/drivers/md/bcache/sysfs.c @@ -16,6 +16,22 @@ #include <linux/sort.h> #include <linux/sched/clock.h> +/* Default is -1; we skip past it for struct cached_dev's cache mode */ +static const char * const bch_cache_modes[] = { + "writethrough", + "writeback", + "writearound", + "none", + NULL +}; + +/* Default is -1; we skip past it for stop_when_cache_set_failed */ +static const char * const bch_stop_on_failure_modes[] = { + "auto", + "always", + NULL +}; + static const char * const cache_replacement_policies[] = { "lru", "fifo", @@ -114,6 +130,20 @@ rw_attribute(btree_shrinker_disabled); rw_attribute(copy_gc_enabled); rw_attribute(size); +static ssize_t bch_snprint_string_list(char *buf, size_t size, const char * const list[], + size_t selected) +{ + char *out = buf; + size_t i; + + for (i = 0; list[i]; i++) + out += snprintf(out, buf + size - out, + i == selected ? "[%s] " : "%s ", list[i]); + + out[-1] = '\n'; + return out - buf; +} + SHOW(__bch_cached_dev) { struct cached_dev *dc = container_of(kobj, struct cached_dev, @@ -124,12 +154,12 @@ SHOW(__bch_cached_dev) if (attr == &sysfs_cache_mode) return bch_snprint_string_list(buf, PAGE_SIZE, - bch_cache_modes + 1, + bch_cache_modes, BDEV_CACHE_MODE(&dc->sb)); if (attr == &sysfs_stop_when_cache_set_failed) return bch_snprint_string_list(buf, PAGE_SIZE, - bch_stop_on_failure_modes + 1, + bch_stop_on_failure_modes, dc->stop_when_cache_set_failed); @@ -253,8 +283,7 @@ STORE(__cached_dev) bch_cached_dev_run(dc); if (attr == &sysfs_cache_mode) { - v = bch_read_string_list(buf, bch_cache_modes + 1); - + v = __sysfs_match_string(bch_cache_modes, -1, buf); if (v < 0) return v; @@ -265,8 +294,7 @@ STORE(__cached_dev) } if (attr == &sysfs_stop_when_cache_set_failed) { - v = bch_read_string_list(buf, bch_stop_on_failure_modes + 1); - + v = __sysfs_match_string(bch_stop_on_failure_modes, -1, buf); if (v < 0) return v; @@ -635,6 +663,7 @@ SHOW_LOCKED(bch_cache_set) STORE(__bch_cache_set) { struct cache_set *c = container_of(kobj, struct cache_set, kobj); + ssize_t v; if (attr == &sysfs_unregister) bch_cache_set_unregister(c); @@ -698,8 +727,7 @@ STORE(__bch_cache_set) c->congested_write_threshold_us); if (attr == &sysfs_errors) { - ssize_t v = bch_read_string_list(buf, error_actions); - + v = __sysfs_match_string(error_actions, -1, buf); if (v < 0) return v; @@ -714,8 +742,7 @@ STORE(__bch_cache_set) c->error_decay = strtoul_or_return(buf) / 88; if (attr == &sysfs_io_disable) { - int v = strtoul_or_return(buf); - + v = strtoul_or_return(buf); if (v) { if (test_and_set_bit(CACHE_SET_IO_DISABLE, &c->flags)) @@ -929,6 +956,7 @@ SHOW_LOCKED(bch_cache) STORE(__bch_cache) { struct cache *ca = container_of(kobj, struct cache, kobj); + ssize_t v; if (attr == &sysfs_discard) { bool v = strtoul_or_return(buf); @@ -943,8 +971,7 @@ STORE(__bch_cache) } if (attr == &sysfs_cache_replacement_policy) { - ssize_t v = bch_read_string_list(buf, cache_replacement_policies); - + v = __sysfs_match_string(cache_replacement_policies, -1, buf); if (v < 0) return v; diff --git a/drivers/md/bcache/util.c b/drivers/md/bcache/util.c index 74febd5230df..fc479b026d6d 100644 --- a/drivers/md/bcache/util.c +++ b/drivers/md/bcache/util.c @@ -120,41 +120,6 @@ ssize_t bch_hprint(char *buf, int64_t v) return sprintf(buf, "%llu.%i%c", q, t * 10 / 1024, units[u]); } -ssize_t bch_snprint_string_list(char *buf, size_t size, const char * const list[], - size_t selected) -{ - char *out = buf; - size_t i; - - for (i = 0; list[i]; i++) - out += snprintf(out, buf + size - out, - i == selected ? "[%s] " : "%s ", list[i]); - - out[-1] = '\n'; - return out - buf; -} - -ssize_t bch_read_string_list(const char *buf, const char * const list[]) -{ - size_t i; - char *s, *d = kstrndup(buf, PAGE_SIZE - 1, GFP_KERNEL); - if (!d) - return -ENOMEM; - - s = strim(d); - - for (i = 0; list[i]; i++) - if (!strcmp(list[i], s)) - break; - - kfree(d); - - if (!list[i]) - return -EINVAL; - - return i; -} - bool bch_is_zero(const char *p, size_t n) { size_t i; diff --git a/drivers/md/bcache/util.h b/drivers/md/bcache/util.h index 268024529edd..cced87f8eb27 100644 --- a/drivers/md/bcache/util.h +++ b/drivers/md/bcache/util.h @@ -365,11 +365,6 @@ ssize_t bch_hprint(char *buf, int64_t v); bool bch_is_zero(const char *p, size_t n); int bch_parse_uuid(const char *s, char *uuid); -ssize_t bch_snprint_string_list(char *buf, size_t size, const char * const list[], - size_t selected); - -ssize_t bch_read_string_list(const char *buf, const char * const list[]); - struct time_stats { spinlock_t lock; /* diff --git a/drivers/md/dm-bio-prison-v1.c b/drivers/md/dm-bio-prison-v1.c index 874841f0fc83..e794e3662fdd 100644 --- a/drivers/md/dm-bio-prison-v1.c +++ b/drivers/md/dm-bio-prison-v1.c @@ -19,7 +19,7 @@ struct dm_bio_prison { spinlock_t lock; - mempool_t *cell_pool; + mempool_t cell_pool; struct rb_root cells; }; @@ -33,15 +33,16 @@ static struct kmem_cache *_cell_cache; */ struct dm_bio_prison *dm_bio_prison_create(void) { - struct dm_bio_prison *prison = kmalloc(sizeof(*prison), GFP_KERNEL); + struct dm_bio_prison *prison = kzalloc(sizeof(*prison), GFP_KERNEL); + int ret; if (!prison) return NULL; spin_lock_init(&prison->lock); - prison->cell_pool = mempool_create_slab_pool(MIN_CELLS, _cell_cache); - if (!prison->cell_pool) { + ret = mempool_init_slab_pool(&prison->cell_pool, MIN_CELLS, _cell_cache); + if (ret) { kfree(prison); return NULL; } @@ -54,21 +55,21 @@ EXPORT_SYMBOL_GPL(dm_bio_prison_create); void dm_bio_prison_destroy(struct dm_bio_prison *prison) { - mempool_destroy(prison->cell_pool); + mempool_exit(&prison->cell_pool); kfree(prison); } EXPORT_SYMBOL_GPL(dm_bio_prison_destroy); struct dm_bio_prison_cell *dm_bio_prison_alloc_cell(struct dm_bio_prison *prison, gfp_t gfp) { - return mempool_alloc(prison->cell_pool, gfp); + return mempool_alloc(&prison->cell_pool, gfp); } EXPORT_SYMBOL_GPL(dm_bio_prison_alloc_cell); void dm_bio_prison_free_cell(struct dm_bio_prison *prison, struct dm_bio_prison_cell *cell) { - mempool_free(cell, prison->cell_pool); + mempool_free(cell, &prison->cell_pool); } EXPORT_SYMBOL_GPL(dm_bio_prison_free_cell); diff --git a/drivers/md/dm-bio-prison-v2.c b/drivers/md/dm-bio-prison-v2.c index 8ce3a1a588cf..f866bc97b032 100644 --- a/drivers/md/dm-bio-prison-v2.c +++ b/drivers/md/dm-bio-prison-v2.c @@ -21,7 +21,7 @@ struct dm_bio_prison_v2 { struct workqueue_struct *wq; spinlock_t lock; - mempool_t *cell_pool; + mempool_t cell_pool; struct rb_root cells; }; @@ -35,7 +35,8 @@ static struct kmem_cache *_cell_cache; */ struct dm_bio_prison_v2 *dm_bio_prison_create_v2(struct workqueue_struct *wq) { - struct dm_bio_prison_v2 *prison = kmalloc(sizeof(*prison), GFP_KERNEL); + struct dm_bio_prison_v2 *prison = kzalloc(sizeof(*prison), GFP_KERNEL); + int ret; if (!prison) return NULL; @@ -43,8 +44,8 @@ struct dm_bio_prison_v2 *dm_bio_prison_create_v2(struct workqueue_struct *wq) prison->wq = wq; spin_lock_init(&prison->lock); - prison->cell_pool = mempool_create_slab_pool(MIN_CELLS, _cell_cache); - if (!prison->cell_pool) { + ret = mempool_init_slab_pool(&prison->cell_pool, MIN_CELLS, _cell_cache); + if (ret) { kfree(prison); return NULL; } @@ -57,21 +58,21 @@ EXPORT_SYMBOL_GPL(dm_bio_prison_create_v2); void dm_bio_prison_destroy_v2(struct dm_bio_prison_v2 *prison) { - mempool_destroy(prison->cell_pool); + mempool_exit(&prison->cell_pool); kfree(prison); } EXPORT_SYMBOL_GPL(dm_bio_prison_destroy_v2); struct dm_bio_prison_cell_v2 *dm_bio_prison_alloc_cell_v2(struct dm_bio_prison_v2 *prison, gfp_t gfp) { - return mempool_alloc(prison->cell_pool, gfp); + return mempool_alloc(&prison->cell_pool, gfp); } EXPORT_SYMBOL_GPL(dm_bio_prison_alloc_cell_v2); void dm_bio_prison_free_cell_v2(struct dm_bio_prison_v2 *prison, struct dm_bio_prison_cell_v2 *cell) { - mempool_free(cell, prison->cell_pool); + mempool_free(cell, &prison->cell_pool); } EXPORT_SYMBOL_GPL(dm_bio_prison_free_cell_v2); diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c index da208638fba4..001c71248246 100644 --- a/drivers/md/dm-cache-target.c +++ b/drivers/md/dm-cache-target.c @@ -447,9 +447,9 @@ struct cache { struct work_struct migration_worker; struct delayed_work waker; struct dm_bio_prison_v2 *prison; - struct bio_set *bs; + struct bio_set bs; - mempool_t *migration_pool; + mempool_t migration_pool; struct dm_cache_policy *policy; unsigned policy_nr_args; @@ -550,7 +550,7 @@ static struct dm_cache_migration *alloc_migration(struct cache *cache) { struct dm_cache_migration *mg; - mg = mempool_alloc(cache->migration_pool, GFP_NOWAIT); + mg = mempool_alloc(&cache->migration_pool, GFP_NOWAIT); if (!mg) return NULL; @@ -569,7 +569,7 @@ static void free_migration(struct dm_cache_migration *mg) if (atomic_dec_and_test(&cache->nr_allocated_migrations)) wake_up(&cache->migration_wait); - mempool_free(mg, cache->migration_pool); + mempool_free(mg, &cache->migration_pool); } /*----------------------------------------------------------------*/ @@ -924,7 +924,7 @@ static void issue_op(struct bio *bio, void *context) static void remap_to_origin_and_cache(struct cache *cache, struct bio *bio, dm_oblock_t oblock, dm_cblock_t cblock) { - struct bio *origin_bio = bio_clone_fast(bio, GFP_NOIO, cache->bs); + struct bio *origin_bio = bio_clone_fast(bio, GFP_NOIO, &cache->bs); BUG_ON(!origin_bio); @@ -2011,7 +2011,7 @@ static void destroy(struct cache *cache) { unsigned i; - mempool_destroy(cache->migration_pool); + mempool_exit(&cache->migration_pool); if (cache->prison) dm_bio_prison_destroy_v2(cache->prison); @@ -2047,8 +2047,7 @@ static void destroy(struct cache *cache) kfree(cache->ctr_args[i]); kfree(cache->ctr_args); - if (cache->bs) - bioset_free(cache->bs); + bioset_exit(&cache->bs); kfree(cache); } @@ -2498,8 +2497,8 @@ static int cache_create(struct cache_args *ca, struct cache **result) cache->features = ca->features; if (writethrough_mode(cache)) { /* Create bioset for writethrough bios issued to origin */ - cache->bs = bioset_create(BIO_POOL_SIZE, 0, 0); - if (!cache->bs) + r = bioset_init(&cache->bs, BIO_POOL_SIZE, 0, 0); + if (r) goto bad; } @@ -2630,9 +2629,9 @@ static int cache_create(struct cache_args *ca, struct cache **result) goto bad; } - cache->migration_pool = mempool_create_slab_pool(MIGRATION_POOL_SIZE, - migration_cache); - if (!cache->migration_pool) { + r = mempool_init_slab_pool(&cache->migration_pool, MIGRATION_POOL_SIZE, + migration_cache); + if (r) { *error = "Error creating cache's migration mempool"; goto bad; } diff --git a/drivers/md/dm-core.h b/drivers/md/dm-core.h index 3222e21cbbf8..f21c5d21bf1b 100644 --- a/drivers/md/dm-core.h +++ b/drivers/md/dm-core.h @@ -91,8 +91,8 @@ struct mapped_device { /* * io objects are allocated from here. */ - struct bio_set *io_bs; - struct bio_set *bs; + struct bio_set io_bs; + struct bio_set bs; /* * freeze/thaw support require holding onto a super block diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 44ff473dab3e..da02f4d8e4b9 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -143,14 +143,14 @@ struct crypt_config { * pool for per bio private data, crypto requests, * encryption requeusts/buffer pages and integrity tags */ - mempool_t *req_pool; - mempool_t *page_pool; - mempool_t *tag_pool; + mempool_t req_pool; + mempool_t page_pool; + mempool_t tag_pool; unsigned tag_pool_max_sectors; struct percpu_counter n_allocated_pages; - struct bio_set *bs; + struct bio_set bs; struct mutex bio_alloc_lock; struct workqueue_struct *io_queue; @@ -1245,7 +1245,7 @@ static void crypt_alloc_req_skcipher(struct crypt_config *cc, unsigned key_index = ctx->cc_sector & (cc->tfms_count - 1); if (!ctx->r.req) - ctx->r.req = mempool_alloc(cc->req_pool, GFP_NOIO); + ctx->r.req = mempool_alloc(&cc->req_pool, GFP_NOIO); skcipher_request_set_tfm(ctx->r.req, cc->cipher_tfm.tfms[key_index]); @@ -1262,7 +1262,7 @@ static void crypt_alloc_req_aead(struct crypt_config *cc, struct convert_context *ctx) { if (!ctx->r.req_aead) - ctx->r.req_aead = mempool_alloc(cc->req_pool, GFP_NOIO); + ctx->r.req_aead = mempool_alloc(&cc->req_pool, GFP_NOIO); aead_request_set_tfm(ctx->r.req_aead, cc->cipher_tfm.tfms_aead[0]); @@ -1290,7 +1290,7 @@ static void crypt_free_req_skcipher(struct crypt_config *cc, struct dm_crypt_io *io = dm_per_bio_data(base_bio, cc->per_bio_data_size); if ((struct skcipher_request *)(io + 1) != req) - mempool_free(req, cc->req_pool); + mempool_free(req, &cc->req_pool); } static void crypt_free_req_aead(struct crypt_config *cc, @@ -1299,7 +1299,7 @@ static void crypt_free_req_aead(struct crypt_config *cc, struct dm_crypt_io *io = dm_per_bio_data(base_bio, cc->per_bio_data_size); if ((struct aead_request *)(io + 1) != req) - mempool_free(req, cc->req_pool); + mempool_free(req, &cc->req_pool); } static void crypt_free_req(struct crypt_config *cc, void *req, struct bio *base_bio) @@ -1409,7 +1409,7 @@ retry: if (unlikely(gfp_mask & __GFP_DIRECT_RECLAIM)) mutex_lock(&cc->bio_alloc_lock); - clone = bio_alloc_bioset(GFP_NOIO, nr_iovecs, cc->bs); + clone = bio_alloc_bioset(GFP_NOIO, nr_iovecs, &cc->bs); if (!clone) goto out; @@ -1418,7 +1418,7 @@ retry: remaining_size = size; for (i = 0; i < nr_iovecs; i++) { - page = mempool_alloc(cc->page_pool, gfp_mask); + page = mempool_alloc(&cc->page_pool, gfp_mask); if (!page) { crypt_free_buffer_pages(cc, clone); bio_put(clone); @@ -1453,7 +1453,7 @@ static void crypt_free_buffer_pages(struct crypt_config *cc, struct bio *clone) bio_for_each_segment_all(bv, clone, i) { BUG_ON(!bv->bv_page); - mempool_free(bv->bv_page, cc->page_pool); + mempool_free(bv->bv_page, &cc->page_pool); } } @@ -1492,7 +1492,7 @@ static void crypt_dec_pending(struct dm_crypt_io *io) crypt_free_req(cc, io->ctx.r.req, base_bio); if (unlikely(io->integrity_metadata_from_pool)) - mempool_free(io->integrity_metadata, io->cc->tag_pool); + mempool_free(io->integrity_metadata, &io->cc->tag_pool); else kfree(io->integrity_metadata); @@ -1565,7 +1565,7 @@ static int kcryptd_io_read(struct dm_crypt_io *io, gfp_t gfp) * biovecs we don't need to worry about the block layer * modifying the biovec array; so leverage bio_clone_fast(). */ - clone = bio_clone_fast(io->base_bio, gfp, cc->bs); + clone = bio_clone_fast(io->base_bio, gfp, &cc->bs); if (!clone) return 1; @@ -2219,15 +2219,13 @@ static void crypt_dtr(struct dm_target *ti) crypt_free_tfms(cc); - if (cc->bs) - bioset_free(cc->bs); + bioset_exit(&cc->bs); - mempool_destroy(cc->page_pool); - mempool_destroy(cc->req_pool); - mempool_destroy(cc->tag_pool); + mempool_exit(&cc->page_pool); + mempool_exit(&cc->req_pool); + mempool_exit(&cc->tag_pool); - if (cc->page_pool) - WARN_ON(percpu_counter_sum(&cc->n_allocated_pages) != 0); + WARN_ON(percpu_counter_sum(&cc->n_allocated_pages) != 0); percpu_counter_destroy(&cc->n_allocated_pages); if (cc->iv_gen_ops && cc->iv_gen_ops->dtr) @@ -2743,8 +2741,6 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) iv_size_padding = align_mask; } - ret = -ENOMEM; - /* ...| IV + padding | original IV | original sec. number | bio tag offset | */ additional_req_size = sizeof(struct dm_crypt_request) + iv_size_padding + cc->iv_size + @@ -2752,8 +2748,8 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) sizeof(uint64_t) + sizeof(unsigned int); - cc->req_pool = mempool_create_kmalloc_pool(MIN_IOS, cc->dmreq_start + additional_req_size); - if (!cc->req_pool) { + ret = mempool_init_kmalloc_pool(&cc->req_pool, MIN_IOS, cc->dmreq_start + additional_req_size); + if (ret) { ti->error = "Cannot allocate crypt request mempool"; goto bad; } @@ -2762,14 +2758,14 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) ALIGN(sizeof(struct dm_crypt_io) + cc->dmreq_start + additional_req_size, ARCH_KMALLOC_MINALIGN); - cc->page_pool = mempool_create(BIO_MAX_PAGES, crypt_page_alloc, crypt_page_free, cc); - if (!cc->page_pool) { + ret = mempool_init(&cc->page_pool, BIO_MAX_PAGES, crypt_page_alloc, crypt_page_free, cc); + if (ret) { ti->error = "Cannot allocate page mempool"; goto bad; } - cc->bs = bioset_create(MIN_IOS, 0, BIOSET_NEED_BVECS); - if (!cc->bs) { + ret = bioset_init(&cc->bs, MIN_IOS, 0, BIOSET_NEED_BVECS); + if (ret) { ti->error = "Cannot allocate crypt bioset"; goto bad; } @@ -2806,11 +2802,10 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) if (!cc->tag_pool_max_sectors) cc->tag_pool_max_sectors = 1; - cc->tag_pool = mempool_create_kmalloc_pool(MIN_IOS, + ret = mempool_init_kmalloc_pool(&cc->tag_pool, MIN_IOS, cc->tag_pool_max_sectors * cc->on_disk_tag_size); - if (!cc->tag_pool) { + if (ret) { ti->error = "Cannot allocate integrity tags mempool"; - ret = -ENOMEM; goto bad; } @@ -2903,7 +2898,7 @@ static int crypt_map(struct dm_target *ti, struct bio *bio) GFP_NOIO | __GFP_NORETRY | __GFP_NOMEMALLOC | __GFP_NOWARN)))) { if (bio_sectors(bio) > cc->tag_pool_max_sectors) dm_accept_partial_bio(bio, cc->tag_pool_max_sectors); - io->integrity_metadata = mempool_alloc(cc->tag_pool, GFP_NOIO); + io->integrity_metadata = mempool_alloc(&cc->tag_pool, GFP_NOIO); io->integrity_metadata_from_pool = true; } } diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c index 514fb4aec5d1..fc68c7aaef8e 100644 --- a/drivers/md/dm-integrity.c +++ b/drivers/md/dm-integrity.c @@ -142,7 +142,7 @@ struct dm_integrity_c { unsigned tag_size; __s8 log2_tag_size; sector_t start; - mempool_t *journal_io_mempool; + mempool_t journal_io_mempool; struct dm_io_client *io; struct dm_bufio_client *bufio; struct workqueue_struct *metadata_wq; @@ -1817,7 +1817,7 @@ static void complete_copy_from_journal(unsigned long error, void *context) struct journal_completion *comp = io->comp; struct dm_integrity_c *ic = comp->ic; remove_range(ic, &io->range); - mempool_free(io, ic->journal_io_mempool); + mempool_free(io, &ic->journal_io_mempool); if (unlikely(error != 0)) dm_integrity_io_error(ic, "copying from journal", -EIO); complete_journal_op(comp); @@ -1886,7 +1886,7 @@ static void do_journal_write(struct dm_integrity_c *ic, unsigned write_start, } next_loop = k - 1; - io = mempool_alloc(ic->journal_io_mempool, GFP_NOIO); + io = mempool_alloc(&ic->journal_io_mempool, GFP_NOIO); io->comp = ∁ io->range.logical_sector = sec; io->range.n_sectors = (k - j) << ic->sb->log2_sectors_per_block; @@ -1918,7 +1918,7 @@ static void do_journal_write(struct dm_integrity_c *ic, unsigned write_start, if (j == k) { remove_range_unlocked(ic, &io->range); spin_unlock_irq(&ic->endio_wait.lock); - mempool_free(io, ic->journal_io_mempool); + mempool_free(io, &ic->journal_io_mempool); goto skip_io; } for (l = j; l < k; l++) { @@ -2980,9 +2980,8 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv) goto bad; } - ic->journal_io_mempool = mempool_create_slab_pool(JOURNAL_IO_MEMPOOL, journal_io_cache); - if (!ic->journal_io_mempool) { - r = -ENOMEM; + r = mempool_init_slab_pool(&ic->journal_io_mempool, JOURNAL_IO_MEMPOOL, journal_io_cache); + if (r) { ti->error = "Cannot allocate mempool"; goto bad; } @@ -3196,7 +3195,7 @@ static void dm_integrity_dtr(struct dm_target *ti) destroy_workqueue(ic->writer_wq); if (ic->bufio) dm_bufio_client_destroy(ic->bufio); - mempool_destroy(ic->journal_io_mempool); + mempool_exit(&ic->journal_io_mempool); if (ic->io) dm_io_client_destroy(ic->io); if (ic->dev) diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c index a8d914d5abbe..81ffc59d05c9 100644 --- a/drivers/md/dm-io.c +++ b/drivers/md/dm-io.c @@ -22,8 +22,8 @@ #define DM_IO_MAX_REGIONS BITS_PER_LONG struct dm_io_client { - mempool_t *pool; - struct bio_set *bios; + mempool_t pool; + struct bio_set bios; }; /* @@ -49,32 +49,33 @@ struct dm_io_client *dm_io_client_create(void) { struct dm_io_client *client; unsigned min_ios = dm_get_reserved_bio_based_ios(); + int ret; - client = kmalloc(sizeof(*client), GFP_KERNEL); + client = kzalloc(sizeof(*client), GFP_KERNEL); if (!client) return ERR_PTR(-ENOMEM); - client->pool = mempool_create_slab_pool(min_ios, _dm_io_cache); - if (!client->pool) + ret = mempool_init_slab_pool(&client->pool, min_ios, _dm_io_cache); + if (ret) goto bad; - client->bios = bioset_create(min_ios, 0, BIOSET_NEED_BVECS); - if (!client->bios) + ret = bioset_init(&client->bios, min_ios, 0, BIOSET_NEED_BVECS); + if (ret) goto bad; return client; bad: - mempool_destroy(client->pool); + mempool_exit(&client->pool); kfree(client); - return ERR_PTR(-ENOMEM); + return ERR_PTR(ret); } EXPORT_SYMBOL(dm_io_client_create); void dm_io_client_destroy(struct dm_io_client *client) { - mempool_destroy(client->pool); - bioset_free(client->bios); + mempool_exit(&client->pool); + bioset_exit(&client->bios); kfree(client); } EXPORT_SYMBOL(dm_io_client_destroy); @@ -120,7 +121,7 @@ static void complete_io(struct io *io) invalidate_kernel_vmap_range(io->vma_invalidate_address, io->vma_invalidate_size); - mempool_free(io, io->client->pool); + mempool_free(io, &io->client->pool); fn(error_bits, context); } @@ -344,7 +345,7 @@ static void do_region(int op, int op_flags, unsigned region, dm_sector_div_up(remaining, (PAGE_SIZE >> SECTOR_SHIFT))); } - bio = bio_alloc_bioset(GFP_NOIO, num_bvecs, io->client->bios); + bio = bio_alloc_bioset(GFP_NOIO, num_bvecs, &io->client->bios); bio->bi_iter.bi_sector = where->sector + (where->count - remaining); bio_set_dev(bio, where->bdev); bio->bi_end_io = endio; @@ -442,7 +443,7 @@ static int sync_io(struct dm_io_client *client, unsigned int num_regions, init_completion(&sio.wait); - io = mempool_alloc(client->pool, GFP_NOIO); + io = mempool_alloc(&client->pool, GFP_NOIO); io->error_bits = 0; atomic_set(&io->count, 1); /* see dispatch_io() */ io->client = client; @@ -474,7 +475,7 @@ static int async_io(struct dm_io_client *client, unsigned int num_regions, return -EIO; } - io = mempool_alloc(client->pool, GFP_NOIO); + io = mempool_alloc(&client->pool, GFP_NOIO); io->error_bits = 0; atomic_set(&io->count, 1); /* see dispatch_io() */ io->client = client; diff --git a/drivers/md/dm-kcopyd.c b/drivers/md/dm-kcopyd.c index e6e7c686646d..ce7efc7434be 100644 --- a/drivers/md/dm-kcopyd.c +++ b/drivers/md/dm-kcopyd.c @@ -47,7 +47,7 @@ struct dm_kcopyd_client { wait_queue_head_t destroyq; atomic_t nr_jobs; - mempool_t *job_pool; + mempool_t job_pool; struct workqueue_struct *kcopyd_wq; struct work_struct kcopyd_work; @@ -479,7 +479,7 @@ static int run_complete_job(struct kcopyd_job *job) */ if (job->master_job == job) { mutex_destroy(&job->lock); - mempool_free(job, kc->job_pool); + mempool_free(job, &kc->job_pool); } fn(read_err, write_err, context); @@ -751,7 +751,7 @@ int dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from, * Allocate an array of jobs consisting of one master job * followed by SPLIT_COUNT sub jobs. */ - job = mempool_alloc(kc->job_pool, GFP_NOIO); + job = mempool_alloc(&kc->job_pool, GFP_NOIO); mutex_init(&job->lock); /* @@ -835,7 +835,7 @@ void *dm_kcopyd_prepare_callback(struct dm_kcopyd_client *kc, { struct kcopyd_job *job; - job = mempool_alloc(kc->job_pool, GFP_NOIO); + job = mempool_alloc(&kc->job_pool, GFP_NOIO); memset(job, 0, sizeof(struct kcopyd_job)); job->kc = kc; @@ -879,10 +879,10 @@ int kcopyd_cancel(struct kcopyd_job *job, int block) *---------------------------------------------------------------*/ struct dm_kcopyd_client *dm_kcopyd_client_create(struct dm_kcopyd_throttle *throttle) { - int r = -ENOMEM; + int r; struct dm_kcopyd_client *kc; - kc = kmalloc(sizeof(*kc), GFP_KERNEL); + kc = kzalloc(sizeof(*kc), GFP_KERNEL); if (!kc) return ERR_PTR(-ENOMEM); @@ -892,14 +892,16 @@ struct dm_kcopyd_client *dm_kcopyd_client_create(struct dm_kcopyd_throttle *thro INIT_LIST_HEAD(&kc->pages_jobs); kc->throttle = throttle; - kc->job_pool = mempool_create_slab_pool(MIN_JOBS, _job_cache); - if (!kc->job_pool) + r = mempool_init_slab_pool(&kc->job_pool, MIN_JOBS, _job_cache); + if (r) goto bad_slab; INIT_WORK(&kc->kcopyd_work, do_work); kc->kcopyd_wq = alloc_workqueue("kcopyd", WQ_MEM_RECLAIM, 0); - if (!kc->kcopyd_wq) + if (!kc->kcopyd_wq) { + r = -ENOMEM; goto bad_workqueue; + } kc->pages = NULL; kc->nr_reserved_pages = kc->nr_free_pages = 0; @@ -923,7 +925,7 @@ bad_io_client: bad_client_pages: destroy_workqueue(kc->kcopyd_wq); bad_workqueue: - mempool_destroy(kc->job_pool); + mempool_exit(&kc->job_pool); bad_slab: kfree(kc); @@ -942,7 +944,7 @@ void dm_kcopyd_client_destroy(struct dm_kcopyd_client *kc) destroy_workqueue(kc->kcopyd_wq); dm_io_client_destroy(kc->io_client); client_free_pages(kc); - mempool_destroy(kc->job_pool); + mempool_exit(&kc->job_pool); kfree(kc); } EXPORT_SYMBOL(dm_kcopyd_client_destroy); diff --git a/drivers/md/dm-log-userspace-base.c b/drivers/md/dm-log-userspace-base.c index 53b7b06d0aa8..52090bee17c2 100644 --- a/drivers/md/dm-log-userspace-base.c +++ b/drivers/md/dm-log-userspace-base.c @@ -76,7 +76,7 @@ struct log_c { */ uint32_t integrated_flush; - mempool_t *flush_entry_pool; + mempool_t flush_entry_pool; }; static struct kmem_cache *_flush_entry_cache; @@ -249,11 +249,10 @@ static int userspace_ctr(struct dm_dirty_log *log, struct dm_target *ti, goto out; } - lc->flush_entry_pool = mempool_create_slab_pool(FLUSH_ENTRY_POOL_SIZE, - _flush_entry_cache); - if (!lc->flush_entry_pool) { + r = mempool_init_slab_pool(&lc->flush_entry_pool, FLUSH_ENTRY_POOL_SIZE, + _flush_entry_cache); + if (r) { DMERR("Failed to create flush_entry_pool"); - r = -ENOMEM; goto out; } @@ -313,7 +312,7 @@ static int userspace_ctr(struct dm_dirty_log *log, struct dm_target *ti, out: kfree(devices_rdata); if (r) { - mempool_destroy(lc->flush_entry_pool); + mempool_exit(&lc->flush_entry_pool); kfree(lc); kfree(ctr_str); } else { @@ -342,7 +341,7 @@ static void userspace_dtr(struct dm_dirty_log *log) if (lc->log_dev) dm_put_device(lc->ti, lc->log_dev); - mempool_destroy(lc->flush_entry_pool); + mempool_exit(&lc->flush_entry_pool); kfree(lc->usr_argv_str); kfree(lc); @@ -570,7 +569,7 @@ static int userspace_flush(struct dm_dirty_log *log) int mark_list_is_empty; int clear_list_is_empty; struct dm_dirty_log_flush_entry *fe, *tmp_fe; - mempool_t *flush_entry_pool = lc->flush_entry_pool; + mempool_t *flush_entry_pool = &lc->flush_entry_pool; spin_lock_irqsave(&lc->flush_lock, flags); list_splice_init(&lc->mark_list, &mark_list); @@ -653,7 +652,7 @@ static void userspace_mark_region(struct dm_dirty_log *log, region_t region) struct dm_dirty_log_flush_entry *fe; /* Wait for an allocation, but _never_ fail */ - fe = mempool_alloc(lc->flush_entry_pool, GFP_NOIO); + fe = mempool_alloc(&lc->flush_entry_pool, GFP_NOIO); BUG_ON(!fe); spin_lock_irqsave(&lc->flush_lock, flags); @@ -687,7 +686,7 @@ static void userspace_clear_region(struct dm_dirty_log *log, region_t region) * to cause the region to be resync'ed when the * device is activated next time. */ - fe = mempool_alloc(lc->flush_entry_pool, GFP_ATOMIC); + fe = mempool_alloc(&lc->flush_entry_pool, GFP_ATOMIC); if (!fe) { DMERR("Failed to allocate memory to clear region."); return; diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 203a0419d2b0..d94ba6f72ff5 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -520,7 +520,8 @@ static int multipath_clone_and_map(struct dm_target *ti, struct request *rq, bdev = pgpath->path.dev->bdev; q = bdev_get_queue(bdev); - clone = blk_get_request(q, rq->cmd_flags | REQ_NOMERGE, GFP_ATOMIC); + clone = blk_get_request(q, rq->cmd_flags | REQ_NOMERGE, + BLK_MQ_REQ_NOWAIT); if (IS_ERR(clone)) { /* EBUSY, ENODEV or EWOULDBLOCK: requeue */ if (blk_queue_dying(q)) { diff --git a/drivers/md/dm-region-hash.c b/drivers/md/dm-region-hash.c index 85c32b22a420..abf3521b80a8 100644 --- a/drivers/md/dm-region-hash.c +++ b/drivers/md/dm-region-hash.c @@ -63,7 +63,7 @@ struct dm_region_hash { /* hash table */ rwlock_t hash_lock; - mempool_t *region_pool; + mempool_t region_pool; unsigned mask; unsigned nr_buckets; unsigned prime; @@ -169,6 +169,7 @@ struct dm_region_hash *dm_region_hash_create( struct dm_region_hash *rh; unsigned nr_buckets, max_buckets; size_t i; + int ret; /* * Calculate a suitable number of buckets for our hash @@ -179,7 +180,7 @@ struct dm_region_hash *dm_region_hash_create( ; nr_buckets >>= 1; - rh = kmalloc(sizeof(*rh), GFP_KERNEL); + rh = kzalloc(sizeof(*rh), GFP_KERNEL); if (!rh) { DMERR("unable to allocate region hash memory"); return ERR_PTR(-ENOMEM); @@ -220,9 +221,9 @@ struct dm_region_hash *dm_region_hash_create( INIT_LIST_HEAD(&rh->failed_recovered_regions); rh->flush_failure = 0; - rh->region_pool = mempool_create_kmalloc_pool(MIN_REGIONS, - sizeof(struct dm_region)); - if (!rh->region_pool) { + ret = mempool_init_kmalloc_pool(&rh->region_pool, MIN_REGIONS, + sizeof(struct dm_region)); + if (ret) { vfree(rh->buckets); kfree(rh); rh = ERR_PTR(-ENOMEM); @@ -242,14 +243,14 @@ void dm_region_hash_destroy(struct dm_region_hash *rh) list_for_each_entry_safe(reg, nreg, rh->buckets + h, hash_list) { BUG_ON(atomic_read(®->pending)); - mempool_free(reg, rh->region_pool); + mempool_free(reg, &rh->region_pool); } } if (rh->log) dm_dirty_log_destroy(rh->log); - mempool_destroy(rh->region_pool); + mempool_exit(&rh->region_pool); vfree(rh->buckets); kfree(rh); } @@ -287,7 +288,7 @@ static struct dm_region *__rh_alloc(struct dm_region_hash *rh, region_t region) { struct dm_region *reg, *nreg; - nreg = mempool_alloc(rh->region_pool, GFP_ATOMIC); + nreg = mempool_alloc(&rh->region_pool, GFP_ATOMIC); if (unlikely(!nreg)) nreg = kmalloc(sizeof(*nreg), GFP_NOIO | __GFP_NOFAIL); @@ -303,7 +304,7 @@ static struct dm_region *__rh_alloc(struct dm_region_hash *rh, region_t region) reg = __rh_lookup(rh, region); if (reg) /* We lost the race. */ - mempool_free(nreg, rh->region_pool); + mempool_free(nreg, &rh->region_pool); else { __rh_insert(rh, nreg); if (nreg->state == DM_RH_CLEAN) { @@ -481,17 +482,17 @@ void dm_rh_update_states(struct dm_region_hash *rh, int errors_handled) list_for_each_entry_safe(reg, next, &recovered, list) { rh->log->type->clear_region(rh->log, reg->key); complete_resync_work(reg, 1); - mempool_free(reg, rh->region_pool); + mempool_free(reg, &rh->region_pool); } list_for_each_entry_safe(reg, next, &failed_recovered, list) { complete_resync_work(reg, errors_handled ? 0 : 1); - mempool_free(reg, rh->region_pool); + mempool_free(reg, &rh->region_pool); } list_for_each_entry_safe(reg, next, &clean, list) { rh->log->type->clear_region(rh->log, reg->key); - mempool_free(reg, rh->region_pool); + mempool_free(reg, &rh->region_pool); } rh->log->type->flush(rh->log); diff --git a/drivers/md/dm-rq.c b/drivers/md/dm-rq.c index bf0b840645cc..6e547b8dd298 100644 --- a/drivers/md/dm-rq.c +++ b/drivers/md/dm-rq.c @@ -406,7 +406,7 @@ static blk_status_t dm_dispatch_clone_request(struct request *clone, struct requ if (blk_queue_io_stat(clone->q)) clone->rq_flags |= RQF_IO_STAT; - clone->start_time = jiffies; + clone->start_time_ns = ktime_get_ns(); r = blk_insert_cloned_request(clone->q, clone); if (r != BLK_STS_OK && r != BLK_STS_RESOURCE && r != BLK_STS_DEV_RESOURCE) /* must complete clone in terms of original request */ @@ -433,7 +433,7 @@ static int setup_clone(struct request *clone, struct request *rq, { int r; - r = blk_rq_prep_clone(clone, rq, tio->md->bs, gfp_mask, + r = blk_rq_prep_clone(clone, rq, &tio->md->bs, gfp_mask, dm_rq_bio_constructor, tio); if (r) return r; diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index 216035be5661..f745404da721 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c @@ -87,7 +87,7 @@ struct dm_snapshot { */ struct list_head out_of_order_list; - mempool_t *pending_pool; + mempool_t pending_pool; struct dm_exception_table pending; struct dm_exception_table complete; @@ -682,7 +682,7 @@ static void free_completed_exception(struct dm_exception *e) static struct dm_snap_pending_exception *alloc_pending_exception(struct dm_snapshot *s) { - struct dm_snap_pending_exception *pe = mempool_alloc(s->pending_pool, + struct dm_snap_pending_exception *pe = mempool_alloc(&s->pending_pool, GFP_NOIO); atomic_inc(&s->pending_exceptions_count); @@ -695,7 +695,7 @@ static void free_pending_exception(struct dm_snap_pending_exception *pe) { struct dm_snapshot *s = pe->snap; - mempool_free(pe, s->pending_pool); + mempool_free(pe, &s->pending_pool); smp_mb__before_atomic(); atomic_dec(&s->pending_exceptions_count); } @@ -1120,7 +1120,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) origin_mode = FMODE_WRITE; } - s = kmalloc(sizeof(*s), GFP_KERNEL); + s = kzalloc(sizeof(*s), GFP_KERNEL); if (!s) { ti->error = "Cannot allocate private snapshot structure"; r = -ENOMEM; @@ -1196,10 +1196,9 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) goto bad_kcopyd; } - s->pending_pool = mempool_create_slab_pool(MIN_IOS, pending_cache); - if (!s->pending_pool) { + r = mempool_init_slab_pool(&s->pending_pool, MIN_IOS, pending_cache); + if (r) { ti->error = "Could not allocate mempool for pending exceptions"; - r = -ENOMEM; goto bad_pending_pool; } @@ -1259,7 +1258,7 @@ bad_read_metadata: unregister_snapshot(s); bad_load_and_register: - mempool_destroy(s->pending_pool); + mempool_exit(&s->pending_pool); bad_pending_pool: dm_kcopyd_client_destroy(s->kcopyd_client); @@ -1355,7 +1354,7 @@ static void snapshot_dtr(struct dm_target *ti) while (atomic_read(&s->pending_exceptions_count)) msleep(1); /* - * Ensure instructions in mempool_destroy aren't reordered + * Ensure instructions in mempool_exit aren't reordered * before atomic_read. */ smp_mb(); @@ -1367,7 +1366,7 @@ static void snapshot_dtr(struct dm_target *ti) __free_exceptions(s); - mempool_destroy(s->pending_pool); + mempool_exit(&s->pending_pool); dm_exception_store_destroy(s->store); diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index b11107497d2e..5772756c63c1 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -260,7 +260,7 @@ struct pool { struct dm_deferred_set *all_io_ds; struct dm_thin_new_mapping *next_mapping; - mempool_t *mapping_pool; + mempool_t mapping_pool; process_bio_fn process_bio; process_bio_fn process_discard; @@ -917,7 +917,7 @@ static void process_prepared_mapping_fail(struct dm_thin_new_mapping *m) { cell_error(m->tc->pool, m->cell); list_del(&m->list); - mempool_free(m, m->tc->pool->mapping_pool); + mempool_free(m, &m->tc->pool->mapping_pool); } static void process_prepared_mapping(struct dm_thin_new_mapping *m) @@ -961,7 +961,7 @@ static void process_prepared_mapping(struct dm_thin_new_mapping *m) out: list_del(&m->list); - mempool_free(m, pool->mapping_pool); + mempool_free(m, &pool->mapping_pool); } /*----------------------------------------------------------------*/ @@ -971,7 +971,7 @@ static void free_discard_mapping(struct dm_thin_new_mapping *m) struct thin_c *tc = m->tc; if (m->cell) cell_defer_no_holder(tc, m->cell); - mempool_free(m, tc->pool->mapping_pool); + mempool_free(m, &tc->pool->mapping_pool); } static void process_prepared_discard_fail(struct dm_thin_new_mapping *m) @@ -999,7 +999,7 @@ static void process_prepared_discard_no_passdown(struct dm_thin_new_mapping *m) bio_endio(m->bio); cell_defer_no_holder(tc, m->cell); - mempool_free(m, tc->pool->mapping_pool); + mempool_free(m, &tc->pool->mapping_pool); } /*----------------------------------------------------------------*/ @@ -1092,7 +1092,7 @@ static void process_prepared_discard_passdown_pt1(struct dm_thin_new_mapping *m) metadata_operation_failed(pool, "dm_thin_remove_range", r); bio_io_error(m->bio); cell_defer_no_holder(tc, m->cell); - mempool_free(m, pool->mapping_pool); + mempool_free(m, &pool->mapping_pool); return; } @@ -1105,7 +1105,7 @@ static void process_prepared_discard_passdown_pt1(struct dm_thin_new_mapping *m) metadata_operation_failed(pool, "dm_pool_inc_data_range", r); bio_io_error(m->bio); cell_defer_no_holder(tc, m->cell); - mempool_free(m, pool->mapping_pool); + mempool_free(m, &pool->mapping_pool); return; } @@ -1150,7 +1150,7 @@ static void process_prepared_discard_passdown_pt2(struct dm_thin_new_mapping *m) bio_endio(m->bio); cell_defer_no_holder(tc, m->cell); - mempool_free(m, pool->mapping_pool); + mempool_free(m, &pool->mapping_pool); } static void process_prepared(struct pool *pool, struct list_head *head, @@ -1196,7 +1196,7 @@ static int ensure_next_mapping(struct pool *pool) if (pool->next_mapping) return 0; - pool->next_mapping = mempool_alloc(pool->mapping_pool, GFP_ATOMIC); + pool->next_mapping = mempool_alloc(&pool->mapping_pool, GFP_ATOMIC); return pool->next_mapping ? 0 : -ENOMEM; } @@ -2835,8 +2835,8 @@ static void __pool_destroy(struct pool *pool) destroy_workqueue(pool->wq); if (pool->next_mapping) - mempool_free(pool->next_mapping, pool->mapping_pool); - mempool_destroy(pool->mapping_pool); + mempool_free(pool->next_mapping, &pool->mapping_pool); + mempool_exit(&pool->mapping_pool); dm_deferred_set_destroy(pool->shared_read_ds); dm_deferred_set_destroy(pool->all_io_ds); kfree(pool); @@ -2861,7 +2861,7 @@ static struct pool *pool_create(struct mapped_device *pool_md, return (struct pool *)pmd; } - pool = kmalloc(sizeof(*pool), GFP_KERNEL); + pool = kzalloc(sizeof(*pool), GFP_KERNEL); if (!pool) { *error = "Error allocating memory for pool"; err_p = ERR_PTR(-ENOMEM); @@ -2931,11 +2931,11 @@ static struct pool *pool_create(struct mapped_device *pool_md, } pool->next_mapping = NULL; - pool->mapping_pool = mempool_create_slab_pool(MAPPING_POOL_SIZE, - _new_mapping_cache); - if (!pool->mapping_pool) { + r = mempool_init_slab_pool(&pool->mapping_pool, MAPPING_POOL_SIZE, + _new_mapping_cache); + if (r) { *error = "Error creating pool's mapping mempool"; - err_p = ERR_PTR(-ENOMEM); + err_p = ERR_PTR(r); goto bad_mapping_pool; } @@ -2955,7 +2955,7 @@ static struct pool *pool_create(struct mapped_device *pool_md, return pool; bad_sort_array: - mempool_destroy(pool->mapping_pool); + mempool_exit(&pool->mapping_pool); bad_mapping_pool: dm_deferred_set_destroy(pool->all_io_ds); bad_all_io_ds: diff --git a/drivers/md/dm-verity-fec.c b/drivers/md/dm-verity-fec.c index e13f90832b6b..684af08d0747 100644 --- a/drivers/md/dm-verity-fec.c +++ b/drivers/md/dm-verity-fec.c @@ -309,13 +309,13 @@ static int fec_alloc_bufs(struct dm_verity *v, struct dm_verity_fec_io *fio) unsigned n; if (!fio->rs) - fio->rs = mempool_alloc(v->fec->rs_pool, GFP_NOIO); + fio->rs = mempool_alloc(&v->fec->rs_pool, GFP_NOIO); fec_for_each_prealloc_buffer(n) { if (fio->bufs[n]) continue; - fio->bufs[n] = mempool_alloc(v->fec->prealloc_pool, GFP_NOWAIT); + fio->bufs[n] = mempool_alloc(&v->fec->prealloc_pool, GFP_NOWAIT); if (unlikely(!fio->bufs[n])) { DMERR("failed to allocate FEC buffer"); return -ENOMEM; @@ -327,7 +327,7 @@ static int fec_alloc_bufs(struct dm_verity *v, struct dm_verity_fec_io *fio) if (fio->bufs[n]) continue; - fio->bufs[n] = mempool_alloc(v->fec->extra_pool, GFP_NOWAIT); + fio->bufs[n] = mempool_alloc(&v->fec->extra_pool, GFP_NOWAIT); /* we can manage with even one buffer if necessary */ if (unlikely(!fio->bufs[n])) break; @@ -335,7 +335,7 @@ static int fec_alloc_bufs(struct dm_verity *v, struct dm_verity_fec_io *fio) fio->nbufs = n; if (!fio->output) - fio->output = mempool_alloc(v->fec->output_pool, GFP_NOIO); + fio->output = mempool_alloc(&v->fec->output_pool, GFP_NOIO); return 0; } @@ -493,15 +493,15 @@ void verity_fec_finish_io(struct dm_verity_io *io) if (!verity_fec_is_enabled(io->v)) return; - mempool_free(fio->rs, f->rs_pool); + mempool_free(fio->rs, &f->rs_pool); fec_for_each_prealloc_buffer(n) - mempool_free(fio->bufs[n], f->prealloc_pool); + mempool_free(fio->bufs[n], &f->prealloc_pool); fec_for_each_extra_buffer(fio, n) - mempool_free(fio->bufs[n], f->extra_pool); + mempool_free(fio->bufs[n], &f->extra_pool); - mempool_free(fio->output, f->output_pool); + mempool_free(fio->output, &f->output_pool); } /* @@ -549,9 +549,9 @@ void verity_fec_dtr(struct dm_verity *v) if (!verity_fec_is_enabled(v)) goto out; - mempool_destroy(f->rs_pool); - mempool_destroy(f->prealloc_pool); - mempool_destroy(f->extra_pool); + mempool_exit(&f->rs_pool); + mempool_exit(&f->prealloc_pool); + mempool_exit(&f->extra_pool); kmem_cache_destroy(f->cache); if (f->data_bufio) @@ -570,7 +570,7 @@ static void *fec_rs_alloc(gfp_t gfp_mask, void *pool_data) { struct dm_verity *v = (struct dm_verity *)pool_data; - return init_rs(8, 0x11d, 0, 1, v->fec->roots); + return init_rs_gfp(8, 0x11d, 0, 1, v->fec->roots, gfp_mask); } static void fec_rs_free(void *element, void *pool_data) @@ -675,6 +675,7 @@ int verity_fec_ctr(struct dm_verity *v) struct dm_verity_fec *f = v->fec; struct dm_target *ti = v->ti; u64 hash_blocks; + int ret; if (!verity_fec_is_enabled(v)) { verity_fec_dtr(v); @@ -770,11 +771,11 @@ int verity_fec_ctr(struct dm_verity *v) } /* Preallocate an rs_control structure for each worker thread */ - f->rs_pool = mempool_create(num_online_cpus(), fec_rs_alloc, - fec_rs_free, (void *) v); - if (!f->rs_pool) { + ret = mempool_init(&f->rs_pool, num_online_cpus(), fec_rs_alloc, + fec_rs_free, (void *) v); + if (ret) { ti->error = "Cannot allocate RS pool"; - return -ENOMEM; + return ret; } f->cache = kmem_cache_create("dm_verity_fec_buffers", @@ -786,26 +787,26 @@ int verity_fec_ctr(struct dm_verity *v) } /* Preallocate DM_VERITY_FEC_BUF_PREALLOC buffers for each thread */ - f->prealloc_pool = mempool_create_slab_pool(num_online_cpus() * - DM_VERITY_FEC_BUF_PREALLOC, - f->cache); - if (!f->prealloc_pool) { + ret = mempool_init_slab_pool(&f->prealloc_pool, num_online_cpus() * + DM_VERITY_FEC_BUF_PREALLOC, + f->cache); + if (ret) { ti->error = "Cannot allocate FEC buffer prealloc pool"; - return -ENOMEM; + return ret; } - f->extra_pool = mempool_create_slab_pool(0, f->cache); - if (!f->extra_pool) { + ret = mempool_init_slab_pool(&f->extra_pool, 0, f->cache); + if (ret) { ti->error = "Cannot allocate FEC buffer extra pool"; - return -ENOMEM; + return ret; } /* Preallocate an output buffer for each thread */ - f->output_pool = mempool_create_kmalloc_pool(num_online_cpus(), - 1 << v->data_dev_block_bits); - if (!f->output_pool) { + ret = mempool_init_kmalloc_pool(&f->output_pool, num_online_cpus(), + 1 << v->data_dev_block_bits); + if (ret) { ti->error = "Cannot allocate FEC output pool"; - return -ENOMEM; + return ret; } /* Reserve space for our per-bio data */ diff --git a/drivers/md/dm-verity-fec.h b/drivers/md/dm-verity-fec.h index bb31ce87a933..6ad803b2b36c 100644 --- a/drivers/md/dm-verity-fec.h +++ b/drivers/md/dm-verity-fec.h @@ -46,10 +46,10 @@ struct dm_verity_fec { sector_t hash_blocks; /* blocks covered after v->hash_start */ unsigned char roots; /* number of parity bytes, M-N of RS(M, N) */ unsigned char rsn; /* N of RS(M, N) */ - mempool_t *rs_pool; /* mempool for fio->rs */ - mempool_t *prealloc_pool; /* mempool for preallocated buffers */ - mempool_t *extra_pool; /* mempool for extra buffers */ - mempool_t *output_pool; /* mempool for output */ + mempool_t rs_pool; /* mempool for fio->rs */ + mempool_t prealloc_pool; /* mempool for preallocated buffers */ + mempool_t extra_pool; /* mempool for extra buffers */ + mempool_t output_pool; /* mempool for output */ struct kmem_cache *cache; /* cache for buffers */ }; diff --git a/drivers/md/dm-zoned-target.c b/drivers/md/dm-zoned-target.c index e73b0776683c..30602d15ad9a 100644 --- a/drivers/md/dm-zoned-target.c +++ b/drivers/md/dm-zoned-target.c @@ -57,7 +57,7 @@ struct dmz_target { struct workqueue_struct *chunk_wq; /* For cloned BIOs to zones */ - struct bio_set *bio_set; + struct bio_set bio_set; /* For flush */ spinlock_t flush_lock; @@ -121,7 +121,7 @@ static int dmz_submit_read_bio(struct dmz_target *dmz, struct dm_zone *zone, } /* Partial BIO: we need to clone the BIO */ - clone = bio_clone_fast(bio, GFP_NOIO, dmz->bio_set); + clone = bio_clone_fast(bio, GFP_NOIO, &dmz->bio_set); if (!clone) return -ENOMEM; @@ -779,10 +779,9 @@ static int dmz_ctr(struct dm_target *ti, unsigned int argc, char **argv) ti->len = (sector_t)dmz_nr_chunks(dmz->metadata) << dev->zone_nr_sectors_shift; /* Zone BIO */ - dmz->bio_set = bioset_create(DMZ_MIN_BIOS, 0, 0); - if (!dmz->bio_set) { + ret = bioset_init(&dmz->bio_set, DMZ_MIN_BIOS, 0, 0); + if (ret) { ti->error = "Create BIO set failed"; - ret = -ENOMEM; goto err_meta; } @@ -828,7 +827,7 @@ err_cwq: destroy_workqueue(dmz->chunk_wq); err_bio: mutex_destroy(&dmz->chunk_lock); - bioset_free(dmz->bio_set); + bioset_exit(&dmz->bio_set); err_meta: dmz_dtr_metadata(dmz->metadata); err_dev: @@ -858,7 +857,7 @@ static void dmz_dtr(struct dm_target *ti) dmz_dtr_metadata(dmz->metadata); - bioset_free(dmz->bio_set); + bioset_exit(&dmz->bio_set); dmz_put_zoned_device(ti); diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 0a7b0107ca78..98dff36b89a3 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -148,8 +148,8 @@ static int dm_numa_node = DM_NUMA_NODE; * For mempools pre-allocation at the table loading time. */ struct dm_md_mempools { - struct bio_set *bs; - struct bio_set *io_bs; + struct bio_set bs; + struct bio_set io_bs; }; struct table_device { @@ -537,7 +537,7 @@ static struct dm_io *alloc_io(struct mapped_device *md, struct bio *bio) struct dm_target_io *tio; struct bio *clone; - clone = bio_alloc_bioset(GFP_NOIO, 0, md->io_bs); + clone = bio_alloc_bioset(GFP_NOIO, 0, &md->io_bs); if (!clone) return NULL; @@ -572,7 +572,7 @@ static struct dm_target_io *alloc_tio(struct clone_info *ci, struct dm_target *t /* the dm_target_io embedded in ci->io is available */ tio = &ci->io->tio; } else { - struct bio *clone = bio_alloc_bioset(gfp_mask, 0, ci->io->md->bs); + struct bio *clone = bio_alloc_bioset(gfp_mask, 0, &ci->io->md->bs); if (!clone) return NULL; @@ -1583,7 +1583,7 @@ static blk_qc_t __split_and_process_bio(struct mapped_device *md, * won't be affected by this reassignment. */ struct bio *b = bio_clone_bioset(bio, GFP_NOIO, - md->queue->bio_split); + &md->queue->bio_split); ci.io->orig_bio = b; bio_advance(bio, (bio_sectors(bio) - ci.sector_count) << 9); bio_chain(b, bio); @@ -1785,10 +1785,8 @@ static void cleanup_mapped_device(struct mapped_device *md) destroy_workqueue(md->wq); if (md->kworker_task) kthread_stop(md->kworker_task); - if (md->bs) - bioset_free(md->bs); - if (md->io_bs) - bioset_free(md->io_bs); + bioset_exit(&md->bs); + bioset_exit(&md->io_bs); if (md->dax_dev) { kill_dax(md->dax_dev); @@ -1965,16 +1963,10 @@ static void __bind_mempools(struct mapped_device *md, struct dm_table *t) * If so, reload bioset because front_pad may have changed * because a different table was loaded. */ - if (md->bs) { - bioset_free(md->bs); - md->bs = NULL; - } - if (md->io_bs) { - bioset_free(md->io_bs); - md->io_bs = NULL; - } + bioset_exit(&md->bs); + bioset_exit(&md->io_bs); - } else if (md->bs) { + } else if (bioset_initialized(&md->bs)) { /* * There's no need to reload with request-based dm * because the size of front_pad doesn't change. @@ -1986,12 +1978,14 @@ static void __bind_mempools(struct mapped_device *md, struct dm_table *t) goto out; } - BUG_ON(!p || md->bs || md->io_bs); + BUG_ON(!p || + bioset_initialized(&md->bs) || + bioset_initialized(&md->io_bs)); md->bs = p->bs; - p->bs = NULL; + memset(&p->bs, 0, sizeof(p->bs)); md->io_bs = p->io_bs; - p->io_bs = NULL; + memset(&p->io_bs, 0, sizeof(p->io_bs)); out: /* mempool bind completed, no longer need any mempools in the table */ dm_table_free_md_mempools(t); @@ -2905,6 +2899,7 @@ struct dm_md_mempools *dm_alloc_md_mempools(struct mapped_device *md, enum dm_qu struct dm_md_mempools *pools = kzalloc_node(sizeof(*pools), GFP_KERNEL, md->numa_node_id); unsigned int pool_size = 0; unsigned int front_pad, io_front_pad; + int ret; if (!pools) return NULL; @@ -2916,10 +2911,10 @@ struct dm_md_mempools *dm_alloc_md_mempools(struct mapped_device *md, enum dm_qu pool_size = max(dm_get_reserved_bio_based_ios(), min_pool_size); front_pad = roundup(per_io_data_size, __alignof__(struct dm_target_io)) + offsetof(struct dm_target_io, clone); io_front_pad = roundup(front_pad, __alignof__(struct dm_io)) + offsetof(struct dm_io, tio); - pools->io_bs = bioset_create(pool_size, io_front_pad, 0); - if (!pools->io_bs) + ret = bioset_init(&pools->io_bs, pool_size, io_front_pad, 0); + if (ret) goto out; - if (integrity && bioset_integrity_create(pools->io_bs, pool_size)) + if (integrity && bioset_integrity_create(&pools->io_bs, pool_size)) goto out; break; case DM_TYPE_REQUEST_BASED: @@ -2932,11 +2927,11 @@ struct dm_md_mempools *dm_alloc_md_mempools(struct mapped_device *md, enum dm_qu BUG(); } - pools->bs = bioset_create(pool_size, front_pad, 0); - if (!pools->bs) + ret = bioset_init(&pools->bs, pool_size, front_pad, 0); + if (ret) goto out; - if (integrity && bioset_integrity_create(pools->bs, pool_size)) + if (integrity && bioset_integrity_create(&pools->bs, pool_size)) goto out; return pools; @@ -2952,10 +2947,8 @@ void dm_free_md_mempools(struct dm_md_mempools *pools) if (!pools) return; - if (pools->bs) - bioset_free(pools->bs); - if (pools->io_bs) - bioset_free(pools->io_bs); + bioset_exit(&pools->bs); + bioset_exit(&pools->io_bs); kfree(pools); } diff --git a/drivers/md/md-faulty.c b/drivers/md/md-faulty.c index 38264b38420f..c2fdf899de14 100644 --- a/drivers/md/md-faulty.c +++ b/drivers/md/md-faulty.c @@ -214,7 +214,7 @@ static bool faulty_make_request(struct mddev *mddev, struct bio *bio) } } if (failit) { - struct bio *b = bio_clone_fast(bio, GFP_NOIO, mddev->bio_set); + struct bio *b = bio_clone_fast(bio, GFP_NOIO, &mddev->bio_set); bio_set_dev(b, conf->rdev->bdev); b->bi_private = bio; diff --git a/drivers/md/md-linear.c b/drivers/md/md-linear.c index 4964323d936b..d45c697c0ebe 100644 --- a/drivers/md/md-linear.c +++ b/drivers/md/md-linear.c @@ -269,7 +269,7 @@ static bool linear_make_request(struct mddev *mddev, struct bio *bio) if (unlikely(bio_end_sector(bio) > end_sector)) { /* This bio crosses a device boundary, so we have to split it */ struct bio *split = bio_split(bio, end_sector - bio_sector, - GFP_NOIO, mddev->bio_set); + GFP_NOIO, &mddev->bio_set); bio_chain(split, bio); generic_make_request(bio); bio = split; diff --git a/drivers/md/md-multipath.c b/drivers/md/md-multipath.c index 0a7e99d62c69..f71fcdb9b39c 100644 --- a/drivers/md/md-multipath.c +++ b/drivers/md/md-multipath.c @@ -80,7 +80,7 @@ static void multipath_end_bh_io(struct multipath_bh *mp_bh, blk_status_t status) bio->bi_status = status; bio_endio(bio); - mempool_free(mp_bh, conf->pool); + mempool_free(mp_bh, &conf->pool); } static void multipath_end_request(struct bio *bio) @@ -117,7 +117,7 @@ static bool multipath_make_request(struct mddev *mddev, struct bio * bio) return true; } - mp_bh = mempool_alloc(conf->pool, GFP_NOIO); + mp_bh = mempool_alloc(&conf->pool, GFP_NOIO); mp_bh->master_bio = bio; mp_bh->mddev = mddev; @@ -125,7 +125,7 @@ static bool multipath_make_request(struct mddev *mddev, struct bio * bio) mp_bh->path = multipath_map(conf); if (mp_bh->path < 0) { bio_io_error(bio); - mempool_free(mp_bh, conf->pool); + mempool_free(mp_bh, &conf->pool); return true; } multipath = conf->multipaths + mp_bh->path; @@ -378,6 +378,7 @@ static int multipath_run (struct mddev *mddev) struct multipath_info *disk; struct md_rdev *rdev; int working_disks; + int ret; if (md_check_no_bitmap(mddev)) return -EINVAL; @@ -431,9 +432,9 @@ static int multipath_run (struct mddev *mddev) } mddev->degraded = conf->raid_disks - working_disks; - conf->pool = mempool_create_kmalloc_pool(NR_RESERVED_BUFS, - sizeof(struct multipath_bh)); - if (conf->pool == NULL) + ret = mempool_init_kmalloc_pool(&conf->pool, NR_RESERVED_BUFS, + sizeof(struct multipath_bh)); + if (ret) goto out_free_conf; mddev->thread = md_register_thread(multipathd, mddev, @@ -455,7 +456,7 @@ static int multipath_run (struct mddev *mddev) return 0; out_free_conf: - mempool_destroy(conf->pool); + mempool_exit(&conf->pool); kfree(conf->multipaths); kfree(conf); mddev->private = NULL; @@ -467,7 +468,7 @@ static void multipath_free(struct mddev *mddev, void *priv) { struct mpconf *conf = priv; - mempool_destroy(conf->pool); + mempool_exit(&conf->pool); kfree(conf->multipaths); kfree(conf); } diff --git a/drivers/md/md-multipath.h b/drivers/md/md-multipath.h index 0adb941f485a..b3099e5fc4d7 100644 --- a/drivers/md/md-multipath.h +++ b/drivers/md/md-multipath.h @@ -13,7 +13,7 @@ struct mpconf { spinlock_t device_lock; struct list_head retry_list; - mempool_t *pool; + mempool_t pool; }; /* diff --git a/drivers/md/md.c b/drivers/md/md.c index c208c01f63a5..fc692b7128bb 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -193,10 +193,10 @@ struct bio *bio_alloc_mddev(gfp_t gfp_mask, int nr_iovecs, { struct bio *b; - if (!mddev || !mddev->bio_set) + if (!mddev || !bioset_initialized(&mddev->bio_set)) return bio_alloc(gfp_mask, nr_iovecs); - b = bio_alloc_bioset(gfp_mask, nr_iovecs, mddev->bio_set); + b = bio_alloc_bioset(gfp_mask, nr_iovecs, &mddev->bio_set); if (!b) return NULL; return b; @@ -205,10 +205,10 @@ EXPORT_SYMBOL_GPL(bio_alloc_mddev); static struct bio *md_bio_alloc_sync(struct mddev *mddev) { - if (!mddev || !mddev->sync_set) + if (!mddev || !bioset_initialized(&mddev->sync_set)) return bio_alloc(GFP_NOIO, 1); - return bio_alloc_bioset(GFP_NOIO, 1, mddev->sync_set); + return bio_alloc_bioset(GFP_NOIO, 1, &mddev->sync_set); } /* @@ -510,7 +510,10 @@ static void mddev_delayed_delete(struct work_struct *ws); static void mddev_put(struct mddev *mddev) { - struct bio_set *bs = NULL, *sync_bs = NULL; + struct bio_set bs, sync_bs; + + memset(&bs, 0, sizeof(bs)); + memset(&sync_bs, 0, sizeof(sync_bs)); if (!atomic_dec_and_lock(&mddev->active, &all_mddevs_lock)) return; @@ -521,8 +524,8 @@ static void mddev_put(struct mddev *mddev) list_del_init(&mddev->all_mddevs); bs = mddev->bio_set; sync_bs = mddev->sync_set; - mddev->bio_set = NULL; - mddev->sync_set = NULL; + memset(&mddev->bio_set, 0, sizeof(mddev->bio_set)); + memset(&mddev->sync_set, 0, sizeof(mddev->sync_set)); if (mddev->gendisk) { /* We did a probe so need to clean up. Call * queue_work inside the spinlock so that @@ -535,10 +538,8 @@ static void mddev_put(struct mddev *mddev) kfree(mddev); } spin_unlock(&all_mddevs_lock); - if (bs) - bioset_free(bs); - if (sync_bs) - bioset_free(sync_bs); + bioset_exit(&bs); + bioset_exit(&sync_bs); } static void md_safemode_timeout(struct timer_list *t); @@ -2123,7 +2124,7 @@ int md_integrity_register(struct mddev *mddev) bdev_get_integrity(reference->bdev)); pr_debug("md: data integrity enabled on %s\n", mdname(mddev)); - if (bioset_integrity_create(mddev->bio_set, BIO_POOL_SIZE)) { + if (bioset_integrity_create(&mddev->bio_set, BIO_POOL_SIZE)) { pr_err("md: failed to create integrity pool for %s\n", mdname(mddev)); return -EINVAL; @@ -5497,17 +5498,15 @@ int md_run(struct mddev *mddev) sysfs_notify_dirent_safe(rdev->sysfs_state); } - if (mddev->bio_set == NULL) { - mddev->bio_set = bioset_create(BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS); - if (!mddev->bio_set) - return -ENOMEM; + if (!bioset_initialized(&mddev->bio_set)) { + err = bioset_init(&mddev->bio_set, BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS); + if (err) + return err; } - if (mddev->sync_set == NULL) { - mddev->sync_set = bioset_create(BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS); - if (!mddev->sync_set) { - err = -ENOMEM; + if (!bioset_initialized(&mddev->sync_set)) { + err = bioset_init(&mddev->sync_set, BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS); + if (err) goto abort; - } } spin_lock(&pers_lock); @@ -5668,14 +5667,8 @@ int md_run(struct mddev *mddev) return 0; abort: - if (mddev->bio_set) { - bioset_free(mddev->bio_set); - mddev->bio_set = NULL; - } - if (mddev->sync_set) { - bioset_free(mddev->sync_set); - mddev->sync_set = NULL; - } + bioset_exit(&mddev->bio_set); + bioset_exit(&mddev->sync_set); return err; } @@ -5888,14 +5881,8 @@ void md_stop(struct mddev *mddev) * This is called from dm-raid */ __md_stop(mddev); - if (mddev->bio_set) { - bioset_free(mddev->bio_set); - mddev->bio_set = NULL; - } - if (mddev->sync_set) { - bioset_free(mddev->sync_set); - mddev->sync_set = NULL; - } + bioset_exit(&mddev->bio_set); + bioset_exit(&mddev->sync_set); } EXPORT_SYMBOL_GPL(md_stop); diff --git a/drivers/md/md.h b/drivers/md/md.h index fbc925cce810..3507cab22cb6 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -452,8 +452,8 @@ struct mddev { struct attribute_group *to_remove; - struct bio_set *bio_set; - struct bio_set *sync_set; /* for sync operations like + struct bio_set bio_set; + struct bio_set sync_set; /* for sync operations like * metadata and bitmap writes */ diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index 584c10347267..65ae47a02218 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -479,7 +479,7 @@ static void raid0_handle_discard(struct mddev *mddev, struct bio *bio) if (bio_end_sector(bio) > zone->zone_end) { struct bio *split = bio_split(bio, zone->zone_end - bio->bi_iter.bi_sector, GFP_NOIO, - mddev->bio_set); + &mddev->bio_set); bio_chain(split, bio); generic_make_request(bio); bio = split; @@ -582,7 +582,8 @@ static bool raid0_make_request(struct mddev *mddev, struct bio *bio) sector = bio_sector; if (sectors < bio_sectors(bio)) { - struct bio *split = bio_split(bio, sectors, GFP_NOIO, mddev->bio_set); + struct bio *split = bio_split(bio, sectors, GFP_NOIO, + &mddev->bio_set); bio_chain(split, bio); generic_make_request(bio); bio = split; diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index e9e3308cb0a7..bad28520719b 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -221,7 +221,7 @@ static void free_r1bio(struct r1bio *r1_bio) struct r1conf *conf = r1_bio->mddev->private; put_all_bios(conf, r1_bio); - mempool_free(r1_bio, conf->r1bio_pool); + mempool_free(r1_bio, &conf->r1bio_pool); } static void put_buf(struct r1bio *r1_bio) @@ -236,7 +236,7 @@ static void put_buf(struct r1bio *r1_bio) rdev_dec_pending(conf->mirrors[i].rdev, r1_bio->mddev); } - mempool_free(r1_bio, conf->r1buf_pool); + mempool_free(r1_bio, &conf->r1buf_pool); lower_barrier(conf, sect); } @@ -1178,7 +1178,7 @@ alloc_r1bio(struct mddev *mddev, struct bio *bio) struct r1conf *conf = mddev->private; struct r1bio *r1_bio; - r1_bio = mempool_alloc(conf->r1bio_pool, GFP_NOIO); + r1_bio = mempool_alloc(&conf->r1bio_pool, GFP_NOIO); /* Ensure no bio records IO_BLOCKED */ memset(r1_bio->bios, 0, conf->raid_disks * sizeof(r1_bio->bios[0])); init_r1bio(r1_bio, mddev, bio); @@ -1268,7 +1268,7 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio, if (max_sectors < bio_sectors(bio)) { struct bio *split = bio_split(bio, max_sectors, - gfp, conf->bio_split); + gfp, &conf->bio_split); bio_chain(split, bio); generic_make_request(bio); bio = split; @@ -1278,7 +1278,7 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio, r1_bio->read_disk = rdisk; - read_bio = bio_clone_fast(bio, gfp, mddev->bio_set); + read_bio = bio_clone_fast(bio, gfp, &mddev->bio_set); r1_bio->bios[rdisk] = read_bio; @@ -1439,7 +1439,7 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio, if (max_sectors < bio_sectors(bio)) { struct bio *split = bio_split(bio, max_sectors, - GFP_NOIO, conf->bio_split); + GFP_NOIO, &conf->bio_split); bio_chain(split, bio); generic_make_request(bio); bio = split; @@ -1479,9 +1479,9 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio, if (r1_bio->behind_master_bio) mbio = bio_clone_fast(r1_bio->behind_master_bio, - GFP_NOIO, mddev->bio_set); + GFP_NOIO, &mddev->bio_set); else - mbio = bio_clone_fast(bio, GFP_NOIO, mddev->bio_set); + mbio = bio_clone_fast(bio, GFP_NOIO, &mddev->bio_set); if (r1_bio->behind_master_bio) { if (test_bit(WriteMostly, &conf->mirrors[i].rdev->flags)) @@ -1657,8 +1657,7 @@ static void close_sync(struct r1conf *conf) _allow_barrier(conf, idx); } - mempool_destroy(conf->r1buf_pool); - conf->r1buf_pool = NULL; + mempool_exit(&conf->r1buf_pool); } static int raid1_spare_active(struct mddev *mddev) @@ -2348,10 +2347,10 @@ static int narrow_write_error(struct r1bio *r1_bio, int i) if (test_bit(R1BIO_BehindIO, &r1_bio->state)) { wbio = bio_clone_fast(r1_bio->behind_master_bio, GFP_NOIO, - mddev->bio_set); + &mddev->bio_set); } else { wbio = bio_clone_fast(r1_bio->master_bio, GFP_NOIO, - mddev->bio_set); + &mddev->bio_set); } bio_set_op_attrs(wbio, REQ_OP_WRITE, 0); @@ -2564,17 +2563,15 @@ static int init_resync(struct r1conf *conf) int buffs; buffs = RESYNC_WINDOW / RESYNC_BLOCK_SIZE; - BUG_ON(conf->r1buf_pool); - conf->r1buf_pool = mempool_create(buffs, r1buf_pool_alloc, r1buf_pool_free, - conf->poolinfo); - if (!conf->r1buf_pool) - return -ENOMEM; - return 0; + BUG_ON(mempool_initialized(&conf->r1buf_pool)); + + return mempool_init(&conf->r1buf_pool, buffs, r1buf_pool_alloc, + r1buf_pool_free, conf->poolinfo); } static struct r1bio *raid1_alloc_init_r1buf(struct r1conf *conf) { - struct r1bio *r1bio = mempool_alloc(conf->r1buf_pool, GFP_NOIO); + struct r1bio *r1bio = mempool_alloc(&conf->r1buf_pool, GFP_NOIO); struct resync_pages *rps; struct bio *bio; int i; @@ -2617,7 +2614,7 @@ static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr, int idx = sector_to_idx(sector_nr); int page_idx = 0; - if (!conf->r1buf_pool) + if (!mempool_initialized(&conf->r1buf_pool)) if (init_resync(conf)) return 0; @@ -2953,14 +2950,13 @@ static struct r1conf *setup_conf(struct mddev *mddev) if (!conf->poolinfo) goto abort; conf->poolinfo->raid_disks = mddev->raid_disks * 2; - conf->r1bio_pool = mempool_create(NR_RAID1_BIOS, r1bio_pool_alloc, - r1bio_pool_free, - conf->poolinfo); - if (!conf->r1bio_pool) + err = mempool_init(&conf->r1bio_pool, NR_RAID1_BIOS, r1bio_pool_alloc, + r1bio_pool_free, conf->poolinfo); + if (err) goto abort; - conf->bio_split = bioset_create(BIO_POOL_SIZE, 0, 0); - if (!conf->bio_split) + err = bioset_init(&conf->bio_split, BIO_POOL_SIZE, 0, 0); + if (err) goto abort; conf->poolinfo->mddev = mddev; @@ -3033,7 +3029,7 @@ static struct r1conf *setup_conf(struct mddev *mddev) abort: if (conf) { - mempool_destroy(conf->r1bio_pool); + mempool_exit(&conf->r1bio_pool); kfree(conf->mirrors); safe_put_page(conf->tmppage); kfree(conf->poolinfo); @@ -3041,8 +3037,7 @@ static struct r1conf *setup_conf(struct mddev *mddev) kfree(conf->nr_waiting); kfree(conf->nr_queued); kfree(conf->barrier); - if (conf->bio_split) - bioset_free(conf->bio_split); + bioset_exit(&conf->bio_split); kfree(conf); } return ERR_PTR(err); @@ -3144,7 +3139,7 @@ static void raid1_free(struct mddev *mddev, void *priv) { struct r1conf *conf = priv; - mempool_destroy(conf->r1bio_pool); + mempool_exit(&conf->r1bio_pool); kfree(conf->mirrors); safe_put_page(conf->tmppage); kfree(conf->poolinfo); @@ -3152,8 +3147,7 @@ static void raid1_free(struct mddev *mddev, void *priv) kfree(conf->nr_waiting); kfree(conf->nr_queued); kfree(conf->barrier); - if (conf->bio_split) - bioset_free(conf->bio_split); + bioset_exit(&conf->bio_split); kfree(conf); } @@ -3199,13 +3193,17 @@ static int raid1_reshape(struct mddev *mddev) * At the same time, we "pack" the devices so that all the missing * devices have the higher raid_disk numbers. */ - mempool_t *newpool, *oldpool; + mempool_t newpool, oldpool; struct pool_info *newpoolinfo; struct raid1_info *newmirrors; struct r1conf *conf = mddev->private; int cnt, raid_disks; unsigned long flags; int d, d2; + int ret; + + memset(&newpool, 0, sizeof(newpool)); + memset(&oldpool, 0, sizeof(oldpool)); /* Cannot change chunk_size, layout, or level */ if (mddev->chunk_sectors != mddev->new_chunk_sectors || @@ -3237,17 +3235,17 @@ static int raid1_reshape(struct mddev *mddev) newpoolinfo->mddev = mddev; newpoolinfo->raid_disks = raid_disks * 2; - newpool = mempool_create(NR_RAID1_BIOS, r1bio_pool_alloc, - r1bio_pool_free, newpoolinfo); - if (!newpool) { + ret = mempool_init(&newpool, NR_RAID1_BIOS, r1bio_pool_alloc, + r1bio_pool_free, newpoolinfo); + if (ret) { kfree(newpoolinfo); - return -ENOMEM; + return ret; } newmirrors = kzalloc(sizeof(struct raid1_info) * raid_disks * 2, GFP_KERNEL); if (!newmirrors) { kfree(newpoolinfo); - mempool_destroy(newpool); + mempool_exit(&newpool); return -ENOMEM; } @@ -3287,7 +3285,7 @@ static int raid1_reshape(struct mddev *mddev) set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); md_wakeup_thread(mddev->thread); - mempool_destroy(oldpool); + mempool_exit(&oldpool); return 0; } diff --git a/drivers/md/raid1.h b/drivers/md/raid1.h index eb84bc68e2fd..e7ccad898736 100644 --- a/drivers/md/raid1.h +++ b/drivers/md/raid1.h @@ -118,10 +118,10 @@ struct r1conf { * mempools - it changes when the array grows or shrinks */ struct pool_info *poolinfo; - mempool_t *r1bio_pool; - mempool_t *r1buf_pool; + mempool_t r1bio_pool; + mempool_t r1buf_pool; - struct bio_set *bio_split; + struct bio_set bio_split; /* temporary buffer to synchronous IO when attempting to repair * a read error. diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 3c60774c8430..37d4b236b81b 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -291,14 +291,14 @@ static void free_r10bio(struct r10bio *r10_bio) struct r10conf *conf = r10_bio->mddev->private; put_all_bios(conf, r10_bio); - mempool_free(r10_bio, conf->r10bio_pool); + mempool_free(r10_bio, &conf->r10bio_pool); } static void put_buf(struct r10bio *r10_bio) { struct r10conf *conf = r10_bio->mddev->private; - mempool_free(r10_bio, conf->r10buf_pool); + mempool_free(r10_bio, &conf->r10buf_pool); lower_barrier(conf); } @@ -1204,7 +1204,7 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio, (unsigned long long)r10_bio->sector); if (max_sectors < bio_sectors(bio)) { struct bio *split = bio_split(bio, max_sectors, - gfp, conf->bio_split); + gfp, &conf->bio_split); bio_chain(split, bio); generic_make_request(bio); bio = split; @@ -1213,7 +1213,7 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio, } slot = r10_bio->read_slot; - read_bio = bio_clone_fast(bio, gfp, mddev->bio_set); + read_bio = bio_clone_fast(bio, gfp, &mddev->bio_set); r10_bio->devs[slot].bio = read_bio; r10_bio->devs[slot].rdev = rdev; @@ -1261,7 +1261,7 @@ static void raid10_write_one_disk(struct mddev *mddev, struct r10bio *r10_bio, } else rdev = conf->mirrors[devnum].rdev; - mbio = bio_clone_fast(bio, GFP_NOIO, mddev->bio_set); + mbio = bio_clone_fast(bio, GFP_NOIO, &mddev->bio_set); if (replacement) r10_bio->devs[n_copy].repl_bio = mbio; else @@ -1509,7 +1509,7 @@ retry_write: if (r10_bio->sectors < bio_sectors(bio)) { struct bio *split = bio_split(bio, r10_bio->sectors, - GFP_NOIO, conf->bio_split); + GFP_NOIO, &conf->bio_split); bio_chain(split, bio); generic_make_request(bio); bio = split; @@ -1533,7 +1533,7 @@ static void __make_request(struct mddev *mddev, struct bio *bio, int sectors) struct r10conf *conf = mddev->private; struct r10bio *r10_bio; - r10_bio = mempool_alloc(conf->r10bio_pool, GFP_NOIO); + r10_bio = mempool_alloc(&conf->r10bio_pool, GFP_NOIO); r10_bio->master_bio = bio; r10_bio->sectors = sectors; @@ -1732,8 +1732,7 @@ static void close_sync(struct r10conf *conf) wait_barrier(conf); allow_barrier(conf); - mempool_destroy(conf->r10buf_pool); - conf->r10buf_pool = NULL; + mempool_exit(&conf->r10buf_pool); } static int raid10_spare_active(struct mddev *mddev) @@ -2583,7 +2582,7 @@ static int narrow_write_error(struct r10bio *r10_bio, int i) if (sectors > sect_to_write) sectors = sect_to_write; /* Write at 'sector' for 'sectors' */ - wbio = bio_clone_fast(bio, GFP_NOIO, mddev->bio_set); + wbio = bio_clone_fast(bio, GFP_NOIO, &mddev->bio_set); bio_trim(wbio, sector - bio->bi_iter.bi_sector, sectors); wsector = r10_bio->devs[i].addr + (sector - r10_bio->sector); wbio->bi_iter.bi_sector = wsector + @@ -2816,25 +2815,25 @@ static void raid10d(struct md_thread *thread) static int init_resync(struct r10conf *conf) { - int buffs; - int i; + int ret, buffs, i; buffs = RESYNC_WINDOW / RESYNC_BLOCK_SIZE; - BUG_ON(conf->r10buf_pool); + BUG_ON(mempool_initialized(&conf->r10buf_pool)); conf->have_replacement = 0; for (i = 0; i < conf->geo.raid_disks; i++) if (conf->mirrors[i].replacement) conf->have_replacement = 1; - conf->r10buf_pool = mempool_create(buffs, r10buf_pool_alloc, r10buf_pool_free, conf); - if (!conf->r10buf_pool) - return -ENOMEM; + ret = mempool_init(&conf->r10buf_pool, buffs, + r10buf_pool_alloc, r10buf_pool_free, conf); + if (ret) + return ret; conf->next_resync = 0; return 0; } static struct r10bio *raid10_alloc_init_r10buf(struct r10conf *conf) { - struct r10bio *r10bio = mempool_alloc(conf->r10buf_pool, GFP_NOIO); + struct r10bio *r10bio = mempool_alloc(&conf->r10buf_pool, GFP_NOIO); struct rsync_pages *rp; struct bio *bio; int nalloc; @@ -2945,7 +2944,7 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr, sector_t chunk_mask = conf->geo.chunk_mask; int page_idx = 0; - if (!conf->r10buf_pool) + if (!mempool_initialized(&conf->r10buf_pool)) if (init_resync(conf)) return 0; @@ -3699,13 +3698,13 @@ static struct r10conf *setup_conf(struct mddev *mddev) conf->geo = geo; conf->copies = copies; - conf->r10bio_pool = mempool_create(NR_RAID10_BIOS, r10bio_pool_alloc, - r10bio_pool_free, conf); - if (!conf->r10bio_pool) + err = mempool_init(&conf->r10bio_pool, NR_RAID10_BIOS, r10bio_pool_alloc, + r10bio_pool_free, conf); + if (err) goto out; - conf->bio_split = bioset_create(BIO_POOL_SIZE, 0, 0); - if (!conf->bio_split) + err = bioset_init(&conf->bio_split, BIO_POOL_SIZE, 0, 0); + if (err) goto out; calc_sectors(conf, mddev->dev_sectors); @@ -3733,6 +3732,7 @@ static struct r10conf *setup_conf(struct mddev *mddev) init_waitqueue_head(&conf->wait_barrier); atomic_set(&conf->nr_pending, 0); + err = -ENOMEM; conf->thread = md_register_thread(raid10d, mddev, "raid10"); if (!conf->thread) goto out; @@ -3742,11 +3742,10 @@ static struct r10conf *setup_conf(struct mddev *mddev) out: if (conf) { - mempool_destroy(conf->r10bio_pool); + mempool_exit(&conf->r10bio_pool); kfree(conf->mirrors); safe_put_page(conf->tmppage); - if (conf->bio_split) - bioset_free(conf->bio_split); + bioset_exit(&conf->bio_split); kfree(conf); } return ERR_PTR(err); @@ -3953,7 +3952,7 @@ static int raid10_run(struct mddev *mddev) out_free_conf: md_unregister_thread(&mddev->thread); - mempool_destroy(conf->r10bio_pool); + mempool_exit(&conf->r10bio_pool); safe_put_page(conf->tmppage); kfree(conf->mirrors); kfree(conf); @@ -3966,13 +3965,12 @@ static void raid10_free(struct mddev *mddev, void *priv) { struct r10conf *conf = priv; - mempool_destroy(conf->r10bio_pool); + mempool_exit(&conf->r10bio_pool); safe_put_page(conf->tmppage); kfree(conf->mirrors); kfree(conf->mirrors_old); kfree(conf->mirrors_new); - if (conf->bio_split) - bioset_free(conf->bio_split); + bioset_exit(&conf->bio_split); kfree(conf); } @@ -4543,7 +4541,7 @@ read_more: * on all the target devices. */ // FIXME - mempool_free(r10_bio, conf->r10buf_pool); + mempool_free(r10_bio, &conf->r10buf_pool); set_bit(MD_RECOVERY_INTR, &mddev->recovery); return sectors_done; } diff --git a/drivers/md/raid10.h b/drivers/md/raid10.h index e2e8840de9bf..d3eaaf3eb1bc 100644 --- a/drivers/md/raid10.h +++ b/drivers/md/raid10.h @@ -93,10 +93,10 @@ struct r10conf { */ wait_queue_head_t wait_barrier; - mempool_t *r10bio_pool; - mempool_t *r10buf_pool; + mempool_t r10bio_pool; + mempool_t r10buf_pool; struct page *tmppage; - struct bio_set *bio_split; + struct bio_set bio_split; /* When taking over an array from a different personality, we store * the new thread here until we fully activate the array. diff --git a/drivers/md/raid5-cache.c b/drivers/md/raid5-cache.c index 3c65f52b68f5..2b775abf377b 100644 --- a/drivers/md/raid5-cache.c +++ b/drivers/md/raid5-cache.c @@ -125,9 +125,9 @@ struct r5l_log { struct list_head no_mem_stripes; /* pending stripes, -ENOMEM */ struct kmem_cache *io_kc; - mempool_t *io_pool; - struct bio_set *bs; - mempool_t *meta_pool; + mempool_t io_pool; + struct bio_set bs; + mempool_t meta_pool; struct md_thread *reclaim_thread; unsigned long reclaim_target; /* number of space that need to be @@ -579,7 +579,7 @@ static void r5l_log_endio(struct bio *bio) md_error(log->rdev->mddev, log->rdev); bio_put(bio); - mempool_free(io->meta_page, log->meta_pool); + mempool_free(io->meta_page, &log->meta_pool); spin_lock_irqsave(&log->io_list_lock, flags); __r5l_set_io_unit_state(io, IO_UNIT_IO_END); @@ -748,7 +748,7 @@ static void r5l_submit_current_io(struct r5l_log *log) static struct bio *r5l_bio_alloc(struct r5l_log *log) { - struct bio *bio = bio_alloc_bioset(GFP_NOIO, BIO_MAX_PAGES, log->bs); + struct bio *bio = bio_alloc_bioset(GFP_NOIO, BIO_MAX_PAGES, &log->bs); bio_set_op_attrs(bio, REQ_OP_WRITE, 0); bio_set_dev(bio, log->rdev->bdev); @@ -780,7 +780,7 @@ static struct r5l_io_unit *r5l_new_meta(struct r5l_log *log) struct r5l_io_unit *io; struct r5l_meta_block *block; - io = mempool_alloc(log->io_pool, GFP_ATOMIC); + io = mempool_alloc(&log->io_pool, GFP_ATOMIC); if (!io) return NULL; memset(io, 0, sizeof(*io)); @@ -791,7 +791,7 @@ static struct r5l_io_unit *r5l_new_meta(struct r5l_log *log) bio_list_init(&io->flush_barriers); io->state = IO_UNIT_RUNNING; - io->meta_page = mempool_alloc(log->meta_pool, GFP_NOIO); + io->meta_page = mempool_alloc(&log->meta_pool, GFP_NOIO); block = page_address(io->meta_page); clear_page(block); block->magic = cpu_to_le32(R5LOG_MAGIC); @@ -1223,7 +1223,7 @@ static bool r5l_complete_finished_ios(struct r5l_log *log) log->next_checkpoint = io->log_start; list_del(&io->log_sibling); - mempool_free(io, log->io_pool); + mempool_free(io, &log->io_pool); r5l_run_no_mem_stripe(log); found = true; @@ -1647,7 +1647,7 @@ static int r5l_recovery_allocate_ra_pool(struct r5l_log *log, { struct page *page; - ctx->ra_bio = bio_alloc_bioset(GFP_KERNEL, BIO_MAX_PAGES, log->bs); + ctx->ra_bio = bio_alloc_bioset(GFP_KERNEL, BIO_MAX_PAGES, &log->bs); if (!ctx->ra_bio) return -ENOMEM; @@ -3066,6 +3066,7 @@ int r5l_init_log(struct r5conf *conf, struct md_rdev *rdev) struct request_queue *q = bdev_get_queue(rdev->bdev); struct r5l_log *log; char b[BDEVNAME_SIZE]; + int ret; pr_debug("md/raid:%s: using device %s as journal\n", mdname(conf->mddev), bdevname(rdev->bdev, b)); @@ -3111,16 +3112,16 @@ int r5l_init_log(struct r5conf *conf, struct md_rdev *rdev) if (!log->io_kc) goto io_kc; - log->io_pool = mempool_create_slab_pool(R5L_POOL_SIZE, log->io_kc); - if (!log->io_pool) + ret = mempool_init_slab_pool(&log->io_pool, R5L_POOL_SIZE, log->io_kc); + if (ret) goto io_pool; - log->bs = bioset_create(R5L_POOL_SIZE, 0, BIOSET_NEED_BVECS); - if (!log->bs) + ret = bioset_init(&log->bs, R5L_POOL_SIZE, 0, BIOSET_NEED_BVECS); + if (ret) goto io_bs; - log->meta_pool = mempool_create_page_pool(R5L_POOL_SIZE, 0); - if (!log->meta_pool) + ret = mempool_init_page_pool(&log->meta_pool, R5L_POOL_SIZE, 0); + if (ret) goto out_mempool; spin_lock_init(&log->tree_lock); @@ -3155,11 +3156,11 @@ int r5l_init_log(struct r5conf *conf, struct md_rdev *rdev) rcu_assign_pointer(conf->log, NULL); md_unregister_thread(&log->reclaim_thread); reclaim_thread: - mempool_destroy(log->meta_pool); + mempool_exit(&log->meta_pool); out_mempool: - bioset_free(log->bs); + bioset_exit(&log->bs); io_bs: - mempool_destroy(log->io_pool); + mempool_exit(&log->io_pool); io_pool: kmem_cache_destroy(log->io_kc); io_kc: @@ -3178,9 +3179,9 @@ void r5l_exit_log(struct r5conf *conf) wake_up(&conf->mddev->sb_wait); flush_work(&log->disable_writeback_work); md_unregister_thread(&log->reclaim_thread); - mempool_destroy(log->meta_pool); - bioset_free(log->bs); - mempool_destroy(log->io_pool); + mempool_exit(&log->meta_pool); + bioset_exit(&log->bs); + mempool_exit(&log->io_pool); kmem_cache_destroy(log->io_kc); kfree(log); } diff --git a/drivers/md/raid5-ppl.c b/drivers/md/raid5-ppl.c index 42890a08375b..3a7c36326589 100644 --- a/drivers/md/raid5-ppl.c +++ b/drivers/md/raid5-ppl.c @@ -105,9 +105,9 @@ struct ppl_conf { atomic64_t seq; /* current log write sequence number */ struct kmem_cache *io_kc; - mempool_t *io_pool; - struct bio_set *bs; - struct bio_set *flush_bs; + mempool_t io_pool; + struct bio_set bs; + struct bio_set flush_bs; /* used only for recovery */ int recovered_entries; @@ -244,7 +244,7 @@ static struct ppl_io_unit *ppl_new_iounit(struct ppl_log *log, struct ppl_header *pplhdr; struct page *header_page; - io = mempool_alloc(ppl_conf->io_pool, GFP_NOWAIT); + io = mempool_alloc(&ppl_conf->io_pool, GFP_NOWAIT); if (!io) return NULL; @@ -503,7 +503,7 @@ static void ppl_submit_iounit(struct ppl_io_unit *io) struct bio *prev = bio; bio = bio_alloc_bioset(GFP_NOIO, BIO_MAX_PAGES, - ppl_conf->bs); + &ppl_conf->bs); bio->bi_opf = prev->bi_opf; bio_copy_dev(bio, prev); bio->bi_iter.bi_sector = bio_end_sector(prev); @@ -570,7 +570,7 @@ static void ppl_io_unit_finished(struct ppl_io_unit *io) list_del(&io->log_sibling); spin_unlock(&log->io_list_lock); - mempool_free(io, ppl_conf->io_pool); + mempool_free(io, &ppl_conf->io_pool); spin_lock(&ppl_conf->no_mem_stripes_lock); if (!list_empty(&ppl_conf->no_mem_stripes)) { @@ -642,7 +642,7 @@ static void ppl_do_flush(struct ppl_io_unit *io) struct bio *bio; char b[BDEVNAME_SIZE]; - bio = bio_alloc_bioset(GFP_NOIO, 0, ppl_conf->flush_bs); + bio = bio_alloc_bioset(GFP_NOIO, 0, &ppl_conf->flush_bs); bio_set_dev(bio, bdev); bio->bi_private = io; bio->bi_opf = REQ_OP_WRITE | REQ_PREFLUSH; @@ -1246,11 +1246,9 @@ static void __ppl_exit_log(struct ppl_conf *ppl_conf) kfree(ppl_conf->child_logs); - if (ppl_conf->bs) - bioset_free(ppl_conf->bs); - if (ppl_conf->flush_bs) - bioset_free(ppl_conf->flush_bs); - mempool_destroy(ppl_conf->io_pool); + bioset_exit(&ppl_conf->bs); + bioset_exit(&ppl_conf->flush_bs); + mempool_exit(&ppl_conf->io_pool); kmem_cache_destroy(ppl_conf->io_kc); kfree(ppl_conf); @@ -1387,24 +1385,18 @@ int ppl_init_log(struct r5conf *conf) goto err; } - ppl_conf->io_pool = mempool_create(conf->raid_disks, ppl_io_pool_alloc, - ppl_io_pool_free, ppl_conf->io_kc); - if (!ppl_conf->io_pool) { - ret = -ENOMEM; + ret = mempool_init(&ppl_conf->io_pool, conf->raid_disks, ppl_io_pool_alloc, + ppl_io_pool_free, ppl_conf->io_kc); + if (ret) goto err; - } - ppl_conf->bs = bioset_create(conf->raid_disks, 0, BIOSET_NEED_BVECS); - if (!ppl_conf->bs) { - ret = -ENOMEM; + ret = bioset_init(&ppl_conf->bs, conf->raid_disks, 0, BIOSET_NEED_BVECS); + if (ret) goto err; - } - ppl_conf->flush_bs = bioset_create(conf->raid_disks, 0, 0); - if (!ppl_conf->flush_bs) { - ret = -ENOMEM; + ret = bioset_init(&ppl_conf->flush_bs, conf->raid_disks, 0, 0); + if (ret) goto err; - } ppl_conf->count = conf->raid_disks; ppl_conf->child_logs = kcalloc(ppl_conf->count, sizeof(struct ppl_log), diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index be117d0a65a8..a2e64989b01f 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -5192,7 +5192,7 @@ static int raid5_read_one_chunk(struct mddev *mddev, struct bio *raid_bio) /* * use bio_clone_fast to make a copy of the bio */ - align_bi = bio_clone_fast(raid_bio, GFP_NOIO, mddev->bio_set); + align_bi = bio_clone_fast(raid_bio, GFP_NOIO, &mddev->bio_set); if (!align_bi) return 0; /* @@ -5277,7 +5277,7 @@ static struct bio *chunk_aligned_read(struct mddev *mddev, struct bio *raid_bio) if (sectors < bio_sectors(raid_bio)) { struct r5conf *conf = mddev->private; - split = bio_split(raid_bio, sectors, GFP_NOIO, conf->bio_split); + split = bio_split(raid_bio, sectors, GFP_NOIO, &conf->bio_split); bio_chain(split, raid_bio); generic_make_request(raid_bio); raid_bio = split; @@ -6773,8 +6773,7 @@ static void free_conf(struct r5conf *conf) if (conf->disks[i].extra_page) put_page(conf->disks[i].extra_page); kfree(conf->disks); - if (conf->bio_split) - bioset_free(conf->bio_split); + bioset_exit(&conf->bio_split); kfree(conf->stripe_hashtbl); kfree(conf->pending_data); kfree(conf); @@ -6853,6 +6852,7 @@ static struct r5conf *setup_conf(struct mddev *mddev) int i; int group_cnt, worker_cnt_per_group; struct r5worker_group *new_group; + int ret; if (mddev->new_level != 5 && mddev->new_level != 4 @@ -6950,8 +6950,8 @@ static struct r5conf *setup_conf(struct mddev *mddev) goto abort; } - conf->bio_split = bioset_create(BIO_POOL_SIZE, 0, 0); - if (!conf->bio_split) + ret = bioset_init(&conf->bio_split, BIO_POOL_SIZE, 0, 0); + if (ret) goto abort; conf->mddev = mddev; diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h index 3f8da26032ac..72e75ba6abf0 100644 --- a/drivers/md/raid5.h +++ b/drivers/md/raid5.h @@ -669,7 +669,7 @@ struct r5conf { int pool_size; /* number of disks in stripeheads in pool */ spinlock_t device_lock; struct disk_info *disks; - struct bio_set *bio_split; + struct bio_set bio_split; /* When taking over an array from a different personality, we store * the new thread here until we fully activate the array. diff --git a/drivers/media/pci/saa7164/saa7164-core.c b/drivers/media/pci/saa7164/saa7164-core.c index fca36a4910c2..d697e1ad929c 100644 --- a/drivers/media/pci/saa7164/saa7164-core.c +++ b/drivers/media/pci/saa7164/saa7164-core.c @@ -1122,23 +1122,11 @@ static int saa7164_proc_show(struct seq_file *m, void *v) return 0; } -static int saa7164_proc_open(struct inode *inode, struct file *filp) -{ - return single_open(filp, saa7164_proc_show, NULL); -} - -static const struct file_operations saa7164_proc_fops = { - .open = saa7164_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static int saa7164_proc_create(void) { struct proc_dir_entry *pe; - pe = proc_create("saa7164", S_IRUGO, NULL, &saa7164_proc_fops); + pe = proc_create_single("saa7164", S_IRUGO, NULL, saa7164_proc_show); if (!pe) return -ENOMEM; diff --git a/drivers/media/pci/zoran/videocodec.c b/drivers/media/pci/zoran/videocodec.c index 5ff23ef89215..4427ae7126e2 100644 --- a/drivers/media/pci/zoran/videocodec.c +++ b/drivers/media/pci/zoran/videocodec.c @@ -344,19 +344,6 @@ static int proc_videocodecs_show(struct seq_file *m, void *v) return 0; } - -static int proc_videocodecs_open(struct inode *inode, struct file *file) -{ - return single_open(file, proc_videocodecs_show, NULL); -} - -static const struct file_operations videocodecs_proc_fops = { - .owner = THIS_MODULE, - .open = proc_videocodecs_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; #endif /* ===================== */ @@ -373,7 +360,8 @@ videocodec_init (void) VIDEOCODEC_VERSION); #ifdef CONFIG_PROC_FS - videocodec_proc_entry = proc_create("videocodecs", 0, NULL, &videocodecs_proc_fops); + videocodec_proc_entry = proc_create_single("videocodecs", 0, NULL, + proc_videocodecs_show); if (!videocodec_proc_entry) { dprintk(1, KERN_ERR "videocodec: can't init procfs.\n"); } diff --git a/drivers/memstick/core/ms_block.c b/drivers/memstick/core/ms_block.c index 57b13dfbd21e..a15181fa45f7 100644 --- a/drivers/memstick/core/ms_block.c +++ b/drivers/memstick/core/ms_block.c @@ -2094,14 +2094,9 @@ static const struct block_device_operations msb_bdops = { static int msb_init_disk(struct memstick_dev *card) { struct msb_data *msb = memstick_get_drvdata(card); - struct memstick_host *host = card->host; int rc; - u64 limit = BLK_BOUNCE_HIGH; unsigned long capacity; - if (host->dev.dma_mask && *(host->dev.dma_mask)) - limit = *(host->dev.dma_mask); - mutex_lock(&msb_disk_lock); msb->disk_id = idr_alloc(&msb_disk_idr, card, 0, 256, GFP_KERNEL); mutex_unlock(&msb_disk_lock); @@ -2123,7 +2118,6 @@ static int msb_init_disk(struct memstick_dev *card) msb->queue->queuedata = card; - blk_queue_bounce_limit(msb->queue, limit); blk_queue_max_hw_sectors(msb->queue, MS_BLOCK_MAX_PAGES); blk_queue_max_segments(msb->queue, MS_BLOCK_MAX_SEGS); blk_queue_max_segment_size(msb->queue, diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c index 8897962781bb..5ee932631fae 100644 --- a/drivers/memstick/core/mspro_block.c +++ b/drivers/memstick/core/mspro_block.c @@ -1170,17 +1170,12 @@ static int mspro_block_init_card(struct memstick_dev *card) static int mspro_block_init_disk(struct memstick_dev *card) { struct mspro_block_data *msb = memstick_get_drvdata(card); - struct memstick_host *host = card->host; struct mspro_devinfo *dev_info = NULL; struct mspro_sys_info *sys_info = NULL; struct mspro_sys_attr *s_attr = NULL; int rc, disk_id; - u64 limit = BLK_BOUNCE_HIGH; unsigned long capacity; - if (host->dev.dma_mask && *(host->dev.dma_mask)) - limit = *(host->dev.dma_mask); - for (rc = 0; msb->attr_group.attrs[rc]; ++rc) { s_attr = mspro_from_sysfs_attr(msb->attr_group.attrs[rc]); @@ -1219,7 +1214,6 @@ static int mspro_block_init_disk(struct memstick_dev *card) msb->queue->queuedata = card; - blk_queue_bounce_limit(msb->queue, limit); blk_queue_max_hw_sectors(msb->queue, MSPRO_BLOCK_MAX_PAGES); blk_queue_max_segments(msb->queue, MSPRO_BLOCK_MAX_SEGS); blk_queue_max_segment_size(msb->queue, diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 51eb1b027963..a746ccdd630a 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -197,9 +197,9 @@ static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_valu static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init); #ifdef CONFIG_PROC_FS -static const struct file_operations mpt_summary_proc_fops; -static const struct file_operations mpt_version_proc_fops; -static const struct file_operations mpt_iocinfo_proc_fops; +static int mpt_summary_proc_show(struct seq_file *m, void *v); +static int mpt_version_proc_show(struct seq_file *m, void *v); +static int mpt_iocinfo_proc_show(struct seq_file *m, void *v); #endif static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc); @@ -2040,8 +2040,10 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) */ dent = proc_mkdir(ioc->name, mpt_proc_root_dir); if (dent) { - proc_create_data("info", S_IRUGO, dent, &mpt_iocinfo_proc_fops, ioc); - proc_create_data("summary", S_IRUGO, dent, &mpt_summary_proc_fops, ioc); + proc_create_single_data("info", S_IRUGO, dent, + mpt_iocinfo_proc_show, ioc); + proc_create_single_data("summary", S_IRUGO, dent, + mpt_summary_proc_show, ioc); } #endif @@ -6606,8 +6608,10 @@ procmpt_create(void) if (mpt_proc_root_dir == NULL) return -ENOTDIR; - proc_create("summary", S_IRUGO, mpt_proc_root_dir, &mpt_summary_proc_fops); - proc_create("version", S_IRUGO, mpt_proc_root_dir, &mpt_version_proc_fops); + proc_create_single("summary", S_IRUGO, mpt_proc_root_dir, + mpt_summary_proc_show); + proc_create_single("version", S_IRUGO, mpt_proc_root_dir, + mpt_version_proc_show); return 0; } @@ -6646,19 +6650,6 @@ static int mpt_summary_proc_show(struct seq_file *m, void *v) return 0; } -static int mpt_summary_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, mpt_summary_proc_show, PDE_DATA(inode)); -} - -static const struct file_operations mpt_summary_proc_fops = { - .owner = THIS_MODULE, - .open = mpt_summary_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static int mpt_version_proc_show(struct seq_file *m, void *v) { u8 cb_idx; @@ -6701,19 +6692,6 @@ static int mpt_version_proc_show(struct seq_file *m, void *v) return 0; } -static int mpt_version_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, mpt_version_proc_show, NULL); -} - -static const struct file_operations mpt_version_proc_fops = { - .owner = THIS_MODULE, - .open = mpt_version_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static int mpt_iocinfo_proc_show(struct seq_file *m, void *v) { MPT_ADAPTER *ioc = m->private; @@ -6793,19 +6771,6 @@ static int mpt_iocinfo_proc_show(struct seq_file *m, void *v) return 0; } - -static int mpt_iocinfo_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, mpt_iocinfo_proc_show, PDE_DATA(inode)); -} - -static const struct file_operations mpt_iocinfo_proc_fops = { - .owner = THIS_MODULE, - .open = mpt_iocinfo_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; #endif /* CONFIG_PROC_FS } */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 86503f60468f..19a5aa70ecda 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -1929,7 +1929,7 @@ static enum blk_eh_timer_return mptsas_eh_timed_out(struct scsi_cmnd *sc) MPT_SCSI_HOST *hd; MPT_ADAPTER *ioc; VirtDevice *vdevice; - enum blk_eh_timer_return rc = BLK_EH_NOT_HANDLED; + enum blk_eh_timer_return rc = BLK_EH_DONE; hd = shost_priv(sc->device->host); if (hd == NULL) { diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c index d61024141e2b..36156a41499c 100644 --- a/drivers/mfd/cros_ec.c +++ b/drivers/mfd/cros_ec.c @@ -229,7 +229,7 @@ int cros_ec_suspend(struct cros_ec_device *ec_dev) } EXPORT_SYMBOL(cros_ec_suspend); -static void cros_ec_drain_events(struct cros_ec_device *ec_dev) +static void cros_ec_report_events_during_suspend(struct cros_ec_device *ec_dev) { while (cros_ec_get_next_event(ec_dev, NULL) > 0) blocking_notifier_call_chain(&ec_dev->event_notifier, @@ -253,21 +253,16 @@ int cros_ec_resume(struct cros_ec_device *ec_dev) dev_dbg(ec_dev->dev, "Error %d sending resume event to ec", ret); - /* - * In some cases, we need to distinguish between events that occur - * during suspend if the EC is not a wake source. For example, - * keypresses during suspend should be discarded if it does not wake - * the system. - * - * If the EC is not a wake source, drain the event queue and mark them - * as "queued during suspend". - */ if (ec_dev->wake_enabled) { disable_irq_wake(ec_dev->irq); ec_dev->wake_enabled = 0; - } else { - cros_ec_drain_events(ec_dev); } + /* + * Let the mfd devices know about events that occur during + * suspend. This way the clients know what to do with them. + */ + cros_ec_report_events_during_suspend(ec_dev); + return 0; } diff --git a/drivers/mfd/cros_ec_spi.c b/drivers/mfd/cros_ec_spi.c index 1b52b8557034..2060d1483043 100644 --- a/drivers/mfd/cros_ec_spi.c +++ b/drivers/mfd/cros_ec_spi.c @@ -419,10 +419,25 @@ static int cros_ec_pkt_xfer_spi(struct cros_ec_device *ec_dev, /* Verify that EC can process command */ for (i = 0; i < len; i++) { rx_byte = rx_buf[i]; + /* + * Seeing the PAST_END, RX_BAD_DATA, or NOT_READY + * markers are all signs that the EC didn't fully + * receive our command. e.g., if the EC is flashing + * itself, it can't respond to any commands and instead + * clocks out EC_SPI_PAST_END from its SPI hardware + * buffer. Similar occurrences can happen if the AP is + * too slow to clock out data after asserting CS -- the + * EC will abort and fill its buffer with + * EC_SPI_RX_BAD_DATA. + * + * In all cases, these errors should be safe to retry. + * Report -EAGAIN and let the caller decide what to do + * about that. + */ if (rx_byte == EC_SPI_PAST_END || rx_byte == EC_SPI_RX_BAD_DATA || rx_byte == EC_SPI_NOT_READY) { - ret = -EREMOTEIO; + ret = -EAGAIN; break; } } @@ -431,7 +446,7 @@ static int cros_ec_pkt_xfer_spi(struct cros_ec_device *ec_dev, if (!ret) ret = cros_ec_spi_receive_packet(ec_dev, ec_msg->insize + sizeof(*response)); - else + else if (ret != -EAGAIN) dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret); final_ret = terminate_request(ec_dev); @@ -537,10 +552,11 @@ static int cros_ec_cmd_xfer_spi(struct cros_ec_device *ec_dev, /* Verify that EC can process command */ for (i = 0; i < len; i++) { rx_byte = rx_buf[i]; + /* See comments in cros_ec_pkt_xfer_spi() */ if (rx_byte == EC_SPI_PAST_END || rx_byte == EC_SPI_RX_BAD_DATA || rx_byte == EC_SPI_NOT_READY) { - ret = -EREMOTEIO; + ret = -EAGAIN; break; } } @@ -549,7 +565,7 @@ static int cros_ec_cmd_xfer_spi(struct cros_ec_device *ec_dev, if (!ret) ret = cros_ec_spi_receive_response(ec_dev, ec_msg->insize + EC_MSG_TX_PROTO_BYTES); - else + else if (ret != -EAGAIN) dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret); final_ret = terminate_request(ec_dev); diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c index d7f54e492aa6..c63e331738c1 100644 --- a/drivers/mfd/mc13xxx-core.c +++ b/drivers/mfd/mc13xxx-core.c @@ -279,8 +279,21 @@ int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode, adc0 = MC13XXX_ADC0_ADINC1 | MC13XXX_ADC0_ADINC2; adc1 = MC13XXX_ADC1_ADEN | MC13XXX_ADC1_ADTRIGIGN | MC13XXX_ADC1_ASC; - if (channel > 7) + /* + * Channels mapped through ADIN7: + * 7 - General purpose ADIN7 + * 16 - UID + * 17 - Die temperature + */ + if (channel > 7 && channel < 16) { adc1 |= MC13XXX_ADC1_ADSEL; + } else if (channel == 16) { + adc0 |= MC13XXX_ADC0_ADIN7SEL_UID; + channel = 7; + } else if (channel == 17) { + adc0 |= MC13XXX_ADC0_ADIN7SEL_DIE; + channel = 7; + } switch (mode) { case MC13XXX_ADC_MODE_TS: diff --git a/drivers/misc/sgi-gru/gruprocfs.c b/drivers/misc/sgi-gru/gruprocfs.c index 4f7635922394..42ea2eccaee9 100644 --- a/drivers/misc/sgi-gru/gruprocfs.c +++ b/drivers/misc/sgi-gru/gruprocfs.c @@ -270,16 +270,6 @@ static int options_open(struct inode *inode, struct file *file) return single_open(file, options_show, NULL); } -static int cch_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &cch_seq_ops); -} - -static int gru_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &gru_seq_ops); -} - /* *INDENT-OFF* */ static const struct file_operations statistics_fops = { .open = statistics_open, @@ -305,73 +295,30 @@ static const struct file_operations options_fops = { .release = single_release, }; -static const struct file_operations cch_fops = { - .open = cch_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; -static const struct file_operations gru_fops = { - .open = gru_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -static struct proc_entry { - char *name; - umode_t mode; - const struct file_operations *fops; - struct proc_dir_entry *entry; -} proc_files[] = { - {"statistics", 0644, &statistics_fops}, - {"mcs_statistics", 0644, &mcs_statistics_fops}, - {"debug_options", 0644, &options_fops}, - {"cch_status", 0444, &cch_fops}, - {"gru_status", 0444, &gru_fops}, - {NULL} -}; -/* *INDENT-ON* */ - static struct proc_dir_entry *proc_gru __read_mostly; -static int create_proc_file(struct proc_entry *p) -{ - p->entry = proc_create(p->name, p->mode, proc_gru, p->fops); - if (!p->entry) - return -1; - return 0; -} - -static void delete_proc_files(void) -{ - struct proc_entry *p; - - if (proc_gru) { - for (p = proc_files; p->name; p++) - if (p->entry) - remove_proc_entry(p->name, proc_gru); - proc_remove(proc_gru); - } -} - int gru_proc_init(void) { - struct proc_entry *p; - proc_gru = proc_mkdir("sgi_uv/gru", NULL); - - for (p = proc_files; p->name; p++) - if (create_proc_file(p)) - goto err; + if (!proc_gru) + return -1; + if (!proc_create("statistics", 0644, proc_gru, &statistics_fops)) + goto err; + if (!proc_create("mcs_statistics", 0644, proc_gru, &mcs_statistics_fops)) + goto err; + if (!proc_create("debug_options", 0644, proc_gru, &options_fops)) + goto err; + if (!proc_create_seq("cch_status", 0444, proc_gru, &cch_seq_ops)) + goto err; + if (!proc_create_seq("gru_status", 0444, proc_gru, &gru_seq_ops)) + goto err; return 0; - err: - delete_proc_files(); + remove_proc_subtree("sgi_uv/gru", NULL); return -1; } void gru_proc_exit(void) { - delete_proc_files(); + remove_proc_subtree("sgi_uv/gru", NULL); } diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 9e923cd1d80e..a0b9102c4c6e 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -244,7 +244,7 @@ static ssize_t power_ro_lock_store(struct device *dev, mq = &md->queue; /* Dispatch locking to the block layer */ - req = blk_get_request(mq->queue, REQ_OP_DRV_OUT, __GFP_RECLAIM); + req = blk_get_request(mq->queue, REQ_OP_DRV_OUT, 0); if (IS_ERR(req)) { count = PTR_ERR(req); goto out_put; @@ -650,8 +650,7 @@ static int mmc_blk_ioctl_cmd(struct mmc_blk_data *md, */ mq = &md->queue; req = blk_get_request(mq->queue, - idata->ic.write_flag ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN, - __GFP_RECLAIM); + idata->ic.write_flag ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN, 0); if (IS_ERR(req)) { err = PTR_ERR(req); goto cmd_done; @@ -721,8 +720,7 @@ static int mmc_blk_ioctl_multi_cmd(struct mmc_blk_data *md, */ mq = &md->queue; req = blk_get_request(mq->queue, - idata[0]->ic.write_flag ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN, - __GFP_RECLAIM); + idata[0]->ic.write_flag ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN, 0); if (IS_ERR(req)) { err = PTR_ERR(req); goto cmd_err; @@ -2353,7 +2351,8 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, set_disk_ro(md->disk, md->read_only || default_ro); md->disk->flags = GENHD_FL_EXT_DEVT; if (area_type & (MMC_BLK_DATA_AREA_RPMB | MMC_BLK_DATA_AREA_BOOT)) - md->disk->flags |= GENHD_FL_NO_PART_SCAN; + md->disk->flags |= GENHD_FL_NO_PART_SCAN + | GENHD_FL_SUPPRESS_PARTITION_INFO; /* * As discussed on lkml, GENHD_FL_REMOVABLE should: @@ -2485,7 +2484,7 @@ static long mmc_rpmb_ioctl(struct file *filp, unsigned int cmd, break; } - return 0; + return ret; } #ifdef CONFIG_COMPAT @@ -2750,7 +2749,7 @@ static int mmc_dbg_card_status_get(void *data, u64 *val) int ret; /* Ask the block layer about the card status */ - req = blk_get_request(mq->queue, REQ_OP_DRV_IN, __GFP_RECLAIM); + req = blk_get_request(mq->queue, REQ_OP_DRV_IN, 0); if (IS_ERR(req)) return PTR_ERR(req); req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_GET_CARD_STATUS; @@ -2786,7 +2785,7 @@ static int mmc_ext_csd_open(struct inode *inode, struct file *filp) return -ENOMEM; /* Ask the block layer for the EXT CSD */ - req = blk_get_request(mq->queue, REQ_OP_DRV_IN, __GFP_RECLAIM); + req = blk_get_request(mq->queue, REQ_OP_DRV_IN, 0); if (IS_ERR(req)) { err = PTR_ERR(req); goto out_free; @@ -2967,9 +2966,11 @@ static void mmc_blk_remove(struct mmc_card *card) mmc_blk_remove_debugfs(card, md); mmc_blk_remove_parts(card, md); pm_runtime_get_sync(&card->dev); - mmc_claim_host(card->host); - mmc_blk_part_switch(card, md->part_type); - mmc_release_host(card->host); + if (md->part_curr != md->part_type) { + mmc_claim_host(card->host); + mmc_blk_part_switch(card, md->part_type); + mmc_release_host(card->host); + } if (card->type != MMC_TYPE_SD_COMBO) pm_runtime_disable(&card->dev); pm_runtime_put_noidle(&card->dev); diff --git a/drivers/mmc/core/card.h b/drivers/mmc/core/card.h index 9c821eedd156..1170feb8f969 100644 --- a/drivers/mmc/core/card.h +++ b/drivers/mmc/core/card.h @@ -149,6 +149,12 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data) card->quirks &= ~data; } +static inline void __maybe_unused add_limit_rate_quirk(struct mmc_card *card, + int data) +{ + card->quirk_max_rate = data; +} + /* * Quirk add/remove for MMC products. */ diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 121ce50b6d5e..281826d1fcca 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -50,9 +50,6 @@ #include "sd_ops.h" #include "sdio_ops.h" -/* If the device is not responding */ -#define MMC_CORE_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */ - /* The max erase timeout, used when host->max_busy_timeout isn't specified */ #define MMC_ERASE_TIMEOUT_MS (60 * 1000) /* 60 s */ @@ -1484,6 +1481,17 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage) } +void mmc_set_initial_signal_voltage(struct mmc_host *host) +{ + /* Try to set signal voltage to 3.3V but fall back to 1.8v or 1.2v */ + if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330)) + dev_dbg(mmc_dev(host), "Initial signal voltage of 3.3v\n"); + else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180)) + dev_dbg(mmc_dev(host), "Initial signal voltage of 1.8v\n"); + else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120)) + dev_dbg(mmc_dev(host), "Initial signal voltage of 1.2v\n"); +} + int mmc_host_set_uhs_voltage(struct mmc_host *host) { u32 clock; @@ -1646,19 +1654,13 @@ void mmc_power_up(struct mmc_host *host, u32 ocr) /* Set initial state and call mmc_set_ios */ mmc_set_initial_state(host); - /* Try to set signal voltage to 3.3V but fall back to 1.8v or 1.2v */ - if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330)) - dev_dbg(mmc_dev(host), "Initial signal voltage of 3.3v\n"); - else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180)) - dev_dbg(mmc_dev(host), "Initial signal voltage of 1.8v\n"); - else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120)) - dev_dbg(mmc_dev(host), "Initial signal voltage of 1.2v\n"); + mmc_set_initial_signal_voltage(host); /* * This delay should be sufficient to allow the power supply * to reach the minimum voltage. */ - mmc_delay(10); + mmc_delay(host->ios.power_delay_ms); mmc_pwrseq_post_power_on(host); @@ -1671,7 +1673,7 @@ void mmc_power_up(struct mmc_host *host, u32 ocr) * This delay must be at least 74 clock sizes, or 1 ms, or the * time required to reach a stable voltage. */ - mmc_delay(10); + mmc_delay(host->ios.power_delay_ms); } void mmc_power_off(struct mmc_host *host) @@ -1967,6 +1969,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, unsigned int qty = 0, busy_timeout = 0; bool use_r1b_resp = false; unsigned long timeout; + int loop_udelay=64, udelay_max=32768; int err; mmc_retune_hold(card->host); @@ -2091,9 +2094,15 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, err = -EIO; goto out; } + if ((cmd.resp[0] & R1_READY_FOR_DATA) && + R1_CURRENT_STATE(cmd.resp[0]) != R1_STATE_PRG) + break; + + usleep_range(loop_udelay, loop_udelay*2); + if (loop_udelay < udelay_max) + loop_udelay *= 2; + } while (1); - } while (!(cmd.resp[0] & R1_READY_FOR_DATA) || - (R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG)); out: mmc_retune_release(card->host); return err; @@ -2435,22 +2444,46 @@ int mmc_hw_reset(struct mmc_host *host) return -EINVAL; mmc_bus_get(host); - if (!host->bus_ops || host->bus_dead || !host->bus_ops->reset) { + if (!host->bus_ops || host->bus_dead || !host->bus_ops->hw_reset) { mmc_bus_put(host); return -EOPNOTSUPP; } - ret = host->bus_ops->reset(host); + ret = host->bus_ops->hw_reset(host); mmc_bus_put(host); if (ret) - pr_warn("%s: tried to reset card, got error %d\n", + pr_warn("%s: tried to HW reset card, got error %d\n", mmc_hostname(host), ret); return ret; } EXPORT_SYMBOL(mmc_hw_reset); +int mmc_sw_reset(struct mmc_host *host) +{ + int ret; + + if (!host->card) + return -EINVAL; + + mmc_bus_get(host); + if (!host->bus_ops || host->bus_dead || !host->bus_ops->sw_reset) { + mmc_bus_put(host); + return -EOPNOTSUPP; + } + + ret = host->bus_ops->sw_reset(host); + mmc_bus_put(host); + + if (ret) + pr_warn("%s: tried to SW reset card, got error %d\n", + mmc_hostname(host), ret); + + return ret; +} +EXPORT_SYMBOL(mmc_sw_reset); + static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) { host->f_init = freq; diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index d6303d69071b..9d8f09ac0821 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -32,7 +32,8 @@ struct mmc_bus_ops { int (*power_restore)(struct mmc_host *); int (*alive)(struct mmc_host *); int (*shutdown)(struct mmc_host *); - int (*reset)(struct mmc_host *); + int (*hw_reset)(struct mmc_host *); + int (*sw_reset)(struct mmc_host *); }; void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops); @@ -51,6 +52,7 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr); int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr); int mmc_host_set_uhs_voltage(struct mmc_host *host); int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage); +void mmc_set_initial_signal_voltage(struct mmc_host *host); void mmc_set_timing(struct mmc_host *host, unsigned int timing); void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type); int mmc_select_drive_strength(struct mmc_card *card, unsigned int max_dtr, diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 64b03d6eaf18..abf9e884386c 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -143,9 +143,6 @@ int mmc_retune(struct mmc_host *host) goto out; return_to_hs400 = true; - - if (host->ops->prepare_hs400_tuning) - host->ops->prepare_hs400_tuning(host, &host->ios); } err = mmc_execute_tuning(host->card); @@ -179,7 +176,7 @@ static void mmc_retune_timer(struct timer_list *t) int mmc_of_parse(struct mmc_host *host) { struct device *dev = host->parent; - u32 bus_width, drv_type; + u32 bus_width, drv_type, cd_debounce_delay_ms; int ret; bool cd_cap_invert, cd_gpio_invert = false; bool ro_cap_invert, ro_gpio_invert = false; @@ -230,11 +227,16 @@ int mmc_of_parse(struct mmc_host *host) } else { cd_cap_invert = device_property_read_bool(dev, "cd-inverted"); + if (device_property_read_u32(dev, "cd-debounce-delay-ms", + &cd_debounce_delay_ms)) + cd_debounce_delay_ms = 200; + if (device_property_read_bool(dev, "broken-cd")) host->caps |= MMC_CAP_NEEDS_POLL; ret = mmc_gpiod_request_cd(host, "cd", 0, true, - 0, &cd_gpio_invert); + cd_debounce_delay_ms, + &cd_gpio_invert); if (!ret) dev_info(host->parent, "Got CD GPIO\n"); else if (ret != -ENOENT && ret != -ENOSYS) @@ -338,6 +340,9 @@ int mmc_of_parse(struct mmc_host *host) host->dsr_req = 0; } + device_property_read_u32(dev, "post-power-on-delay-ms", + &host->ios.power_delay_ms); + return mmc_pwrseq_alloc(host); } @@ -403,6 +408,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) host->max_blk_count = PAGE_SIZE / 512; host->fixed_drv_type = -EINVAL; + host->ios.power_delay_ms = 10; return host; } diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 6f8ebd6caa4c..4466f5de54d4 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1282,6 +1282,10 @@ int mmc_hs400_to_hs200(struct mmc_card *card) mmc_set_bus_speed(card); + /* Prepare tuning for HS400 mode. */ + if (host->ops->prepare_hs400_tuning) + host->ops->prepare_hs400_tuning(host, &host->ios); + return 0; out_err: @@ -1830,6 +1834,14 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, } } + if (host->caps2 & MMC_CAP2_AVOID_3_3V && + host->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_330) { + pr_err("%s: Host failed to negotiate down from 3.3V\n", + mmc_hostname(host)); + err = -EINVAL; + goto free_card; + } + if (!oldcard) host->card = card; @@ -2117,7 +2129,7 @@ static int mmc_can_reset(struct mmc_card *card) return 1; } -static int mmc_reset(struct mmc_host *host) +static int _mmc_hw_reset(struct mmc_host *host) { struct mmc_card *card = host->card; @@ -2151,7 +2163,7 @@ static const struct mmc_bus_ops mmc_ops = { .runtime_resume = mmc_runtime_resume, .alive = mmc_alive, .shutdown = mmc_shutdown, - .reset = mmc_reset, + .hw_reset = _mmc_hw_reset, }; /* diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c index 13ef162cf066..a8b9fee4d62a 100644 --- a/drivers/mmc/core/pwrseq_simple.c +++ b/drivers/mmc/core/pwrseq_simple.c @@ -40,14 +40,18 @@ static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq, struct gpio_descs *reset_gpios = pwrseq->reset_gpios; if (!IS_ERR(reset_gpios)) { - int i; - int values[reset_gpios->ndescs]; + int i, *values; + int nvalues = reset_gpios->ndescs; - for (i = 0; i < reset_gpios->ndescs; i++) + values = kmalloc_array(nvalues, sizeof(int), GFP_KERNEL); + if (!values) + return; + + for (i = 0; i < nvalues; i++) values[i] = value; - gpiod_set_array_value_cansleep( - reset_gpios->ndescs, reset_gpios->desc, values); + gpiod_set_array_value_cansleep(nvalues, reset_gpios->desc, values); + kfree(values); } } diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c index 56e9a803db21..648eb6743ed5 100644 --- a/drivers/mmc/core/queue.c +++ b/drivers/mmc/core/queue.c @@ -111,8 +111,9 @@ static enum blk_eh_timer_return mmc_cqe_timed_out(struct request *req) __mmc_cqe_recovery_notifier(mq); return BLK_EH_RESET_TIMER; } - /* No timeout */ - return BLK_EH_HANDLED; + /* No timeout (XXX: huh? comment doesn't make much sense) */ + blk_mq_complete_request(req); + return BLK_EH_DONE; default: /* Timeout is handled by mmc core */ return BLK_EH_RESET_TIMER; diff --git a/drivers/mmc/core/quirks.h b/drivers/mmc/core/quirks.h index 5153577754f0..dd2f73af8f2c 100644 --- a/drivers/mmc/core/quirks.h +++ b/drivers/mmc/core/quirks.h @@ -132,6 +132,9 @@ static const struct mmc_fixup sdio_fixup_methods[] = { SDIO_FIXUP(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8797_F0, add_quirk, MMC_QUIRK_BROKEN_IRQ_POLLING), + SDIO_FIXUP(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8887WLAN, + add_limit_rate_quirk, 150000000), + END_FIXUP }; diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index baf3d5da4ccb..d0d9f90e7cdf 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -1058,6 +1058,14 @@ retry: mmc_set_bus_width(host, MMC_BUS_WIDTH_4); } } + + if (host->caps2 & MMC_CAP2_AVOID_3_3V && + host->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_330) { + pr_err("%s: Host failed to negotiate down from 3.3V\n", + mmc_hostname(host)); + err = -EINVAL; + goto free_card; + } done: host->card = card; return 0; @@ -1214,7 +1222,7 @@ static int mmc_sd_runtime_resume(struct mmc_host *host) return 0; } -static int mmc_sd_reset(struct mmc_host *host) +static int mmc_sd_hw_reset(struct mmc_host *host) { mmc_power_cycle(host, host->card->ocr); return mmc_sd_init_card(host, host->card->ocr, host->card); @@ -1229,7 +1237,7 @@ static const struct mmc_bus_ops mmc_sd_ops = { .resume = mmc_sd_resume, .alive = mmc_sd_alive, .shutdown = mmc_sd_suspend, - .reset = mmc_sd_reset, + .hw_reset = mmc_sd_hw_reset, }; /* diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index c599a628a387..a86490dbca70 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -444,6 +444,7 @@ static int sdio_set_bus_speed_mode(struct mmc_card *card) unsigned int bus_speed, timing; int err; unsigned char speed; + unsigned int max_rate; /* * If the host doesn't support any of the UHS-I modes, fallback on @@ -500,9 +501,12 @@ static int sdio_set_bus_speed_mode(struct mmc_card *card) if (err) return err; + max_rate = min_not_zero(card->quirk_max_rate, + card->sw_caps.uhs_max_dtr); + if (bus_speed) { mmc_set_timing(card->host, timing); - mmc_set_clock(card->host, card->sw_caps.uhs_max_dtr); + mmc_set_clock(card->host, max_rate); } return 0; @@ -788,6 +792,14 @@ try_again: if (err) goto remove; } + + if (host->caps2 & MMC_CAP2_AVOID_3_3V && + host->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_330) { + pr_err("%s: Host failed to negotiate down from 3.3V\n", + mmc_hostname(host)); + err = -EINVAL; + goto remove; + } finish: if (!oldcard) host->card = card; @@ -801,6 +813,22 @@ err: return err; } +static int mmc_sdio_reinit_card(struct mmc_host *host, bool powered_resume) +{ + int ret; + + sdio_reset(host); + mmc_go_idle(host); + mmc_send_if_cond(host, host->card->ocr); + + ret = mmc_send_io_op_cond(host, 0, NULL); + if (ret) + return ret; + + return mmc_sdio_init_card(host, host->card->ocr, host->card, + powered_resume); +} + /* * Host is being removed. Free up the current card. */ @@ -948,14 +976,7 @@ static int mmc_sdio_resume(struct mmc_host *host) /* No need to reinitialize powered-resumed nonremovable cards */ if (mmc_card_is_removable(host) || !mmc_card_keep_power(host)) { - sdio_reset(host); - mmc_go_idle(host); - mmc_send_if_cond(host, host->card->ocr); - err = mmc_send_io_op_cond(host, 0, NULL); - if (!err) - err = mmc_sdio_init_card(host, host->card->ocr, - host->card, - mmc_card_keep_power(host)); + err = mmc_sdio_reinit_card(host, mmc_card_keep_power(host)); } else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) { /* We may have switched to 1-bit mode during suspend */ err = sdio_enable_4bit_bus(host->card); @@ -978,8 +999,6 @@ static int mmc_sdio_power_restore(struct mmc_host *host) { int ret; - mmc_claim_host(host); - /* * Reset the card by performing the same steps that are taken by * mmc_rescan_try_freq() and mmc_attach_sdio() during a "normal" probe. @@ -997,20 +1016,12 @@ static int mmc_sdio_power_restore(struct mmc_host *host) * */ - sdio_reset(host); - mmc_go_idle(host); - mmc_send_if_cond(host, host->card->ocr); - - ret = mmc_send_io_op_cond(host, 0, NULL); - if (ret) - goto out; + mmc_claim_host(host); - ret = mmc_sdio_init_card(host, host->card->ocr, host->card, - mmc_card_keep_power(host)); + ret = mmc_sdio_reinit_card(host, mmc_card_keep_power(host)); if (!ret && host->sdio_irqs) mmc_signal_sdio_irq(host); -out: mmc_release_host(host); return ret; @@ -1039,12 +1050,24 @@ static int mmc_sdio_runtime_resume(struct mmc_host *host) return ret; } -static int mmc_sdio_reset(struct mmc_host *host) +static int mmc_sdio_hw_reset(struct mmc_host *host) { mmc_power_cycle(host, host->card->ocr); return mmc_sdio_power_restore(host); } +static int mmc_sdio_sw_reset(struct mmc_host *host) +{ + mmc_set_clock(host, host->f_init); + sdio_reset(host); + mmc_go_idle(host); + + mmc_set_initial_state(host); + mmc_set_initial_signal_voltage(host); + + return mmc_sdio_reinit_card(host, 0); +} + static const struct mmc_bus_ops mmc_sdio_ops = { .remove = mmc_sdio_remove, .detect = mmc_sdio_detect, @@ -1055,7 +1078,8 @@ static const struct mmc_bus_ops mmc_sdio_ops = { .runtime_resume = mmc_sdio_runtime_resume, .power_restore = mmc_sdio_power_restore, .alive = mmc_sdio_alive, - .reset = mmc_sdio_reset, + .hw_reset = mmc_sdio_hw_reset, + .sw_reset = mmc_sdio_sw_reset, }; diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 2b32b88949ba..b6d8203e46eb 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -139,7 +139,7 @@ static int sdio_bus_probe(struct device *dev) return -ENODEV; ret = dev_pm_domain_attach(dev, false); - if (ret == -EPROBE_DEFER) + if (ret) return ret; /* Unbound SDIO functions are always suspended. diff --git a/drivers/mmc/core/sdio_uart.c b/drivers/mmc/core/sdio_uart.c index d3c91f412b69..25e113001a3c 100644 --- a/drivers/mmc/core/sdio_uart.c +++ b/drivers/mmc/core/sdio_uart.c @@ -1008,19 +1008,6 @@ static int sdio_uart_proc_show(struct seq_file *m, void *v) return 0; } -static int sdio_uart_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, sdio_uart_proc_show, NULL); -} - -static const struct file_operations sdio_uart_proc_fops = { - .owner = THIS_MODULE, - .open = sdio_uart_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static const struct tty_port_operations sdio_uart_port_ops = { .dtr_rts = uart_dtr_rts, .carrier_raised = uart_carrier_raised, @@ -1045,7 +1032,7 @@ static const struct tty_operations sdio_uart_ops = { .tiocmset = sdio_uart_tiocmset, .install = sdio_uart_install, .cleanup = sdio_uart_cleanup, - .proc_fops = &sdio_uart_proc_fops, + .proc_show = sdio_uart_proc_show, }; static struct tty_driver *sdio_uart_tty_driver; diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c index 31f7dbb15668..ef05e0039378 100644 --- a/drivers/mmc/core/slot-gpio.c +++ b/drivers/mmc/core/slot-gpio.c @@ -28,15 +28,17 @@ struct mmc_gpio { irqreturn_t (*cd_gpio_isr)(int irq, void *dev_id); char *ro_label; char cd_label[0]; + u32 cd_debounce_delay_ms; }; static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id) { /* Schedule a card detection after a debounce timeout */ struct mmc_host *host = dev_id; + struct mmc_gpio *ctx = host->slot.handler_priv; host->trigger_card_event = true; - mmc_detect_change(host, msecs_to_jiffies(200)); + mmc_detect_change(host, msecs_to_jiffies(ctx->cd_debounce_delay_ms)); return IRQ_HANDLED; } @@ -49,6 +51,7 @@ int mmc_gpio_alloc(struct mmc_host *host) if (ctx) { ctx->ro_label = ctx->cd_label + len; + ctx->cd_debounce_delay_ms = 200; snprintf(ctx->cd_label, len, "%s cd", dev_name(host->parent)); snprintf(ctx->ro_label, len, "%s ro", dev_name(host->parent)); host->slot.handler_priv = ctx; @@ -76,15 +79,22 @@ EXPORT_SYMBOL(mmc_gpio_get_ro); int mmc_gpio_get_cd(struct mmc_host *host) { struct mmc_gpio *ctx = host->slot.handler_priv; + int cansleep; if (!ctx || !ctx->cd_gpio) return -ENOSYS; - if (ctx->override_cd_active_level) - return !gpiod_get_raw_value_cansleep(ctx->cd_gpio) ^ - !!(host->caps2 & MMC_CAP2_CD_ACTIVE_HIGH); + cansleep = gpiod_cansleep(ctx->cd_gpio); + if (ctx->override_cd_active_level) { + int value = cansleep ? + gpiod_get_raw_value_cansleep(ctx->cd_gpio) : + gpiod_get_raw_value(ctx->cd_gpio); + return !value ^ !!(host->caps2 & MMC_CAP2_CD_ACTIVE_HIGH); + } - return gpiod_get_value_cansleep(ctx->cd_gpio); + return cansleep ? + gpiod_get_value_cansleep(ctx->cd_gpio) : + gpiod_get_value(ctx->cd_gpio); } EXPORT_SYMBOL(mmc_gpio_get_cd); @@ -261,7 +271,7 @@ int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id, if (debounce) { ret = gpiod_set_debounce(desc, debounce); if (ret < 0) - return ret; + ctx->cd_debounce_delay_ms = debounce; } if (gpio_invert) diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 9589f9c9046f..0581c199c996 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -345,11 +345,11 @@ config MMC_SDHCI_IPROC If unsure, say N. config MMC_MESON_GX - tristate "Amlogic S905/GX* SD/MMC Host Controller support" + tristate "Amlogic S905/GX*/AXG SD/MMC Host Controller support" depends on ARCH_MESON && MMC help This selects support for the Amlogic SD/MMC Host Controller - found on the S905/GX* family of SoCs. This controller is + found on the S905/GX*/AXG family of SoCs. This controller is MMC 5.1 compliant and supports SD, eMMC and SDIO interfaces. If you have a controller with this interface, say Y here. @@ -358,7 +358,6 @@ config MMC_MESON_MX_SDIO tristate "Amlogic Meson6/Meson8/Meson8b SD/MMC Host Controller support" depends on ARCH_MESON || COMPILE_TEST depends on COMMON_CLK - depends on HAS_DMA depends on OF help This selects support for the SD/MMC Host Controller on @@ -401,7 +400,6 @@ config MMC_OMAP config MMC_OMAP_HS tristate "TI OMAP High Speed Multimedia Card Interface support" - depends on HAS_DMA depends on ARCH_OMAP2PLUS || ARCH_KEYSTONE || COMPILE_TEST help This selects the TI OMAP High Speed Multimedia card Interface. @@ -511,7 +509,6 @@ config MMC_DAVINCI config MMC_GOLDFISH tristate "goldfish qemu Multimedia Card Interface support" - depends on HAS_DMA depends on GOLDFISH || COMPILE_TEST help This selects the Goldfish Multimedia card Interface emulation @@ -605,7 +602,7 @@ config MMC_SDHI config MMC_SDHI_SYS_DMAC tristate "DMA for SDHI SD/SDIO controllers using SYS-DMAC" - depends on MMC_SDHI && HAS_DMA + depends on MMC_SDHI default MMC_SDHI if (SUPERH || ARM) help This provides DMA support for SDHI SD/SDIO controllers @@ -615,7 +612,7 @@ config MMC_SDHI_SYS_DMAC config MMC_SDHI_INTERNAL_DMAC tristate "DMA for SDHI SD/SDIO controllers using on-chip bus mastering" depends on ARM64 || COMPILE_TEST - depends on MMC_SDHI && HAS_DMA + depends on MMC_SDHI default MMC_SDHI if ARM64 help This provides DMA support for SDHI SD/SDIO controllers @@ -669,7 +666,6 @@ config MMC_CAVIUM_THUNDERX config MMC_DW tristate "Synopsys DesignWare Memory Card Interface" - depends on HAS_DMA depends on ARC || ARM || ARM64 || MIPS || COMPILE_TEST help This selects support for the Synopsys DesignWare Mobile Storage IP @@ -690,6 +686,15 @@ config MMC_DW_PLTFM If unsure, say Y. +config MMC_DW_BLUEFIELD + tristate "BlueField specific extensions for Synopsys DW Memory Card Interface" + depends on MMC_DW + select MMC_DW_PLTFM + help + This selects support for Mellanox BlueField SoC specific extensions to + the Synopsys DesignWare Memory Card Interface driver. Select this + option for platforms based on Mellanox BlueField SoC's. + config MMC_DW_EXYNOS tristate "Exynos specific extensions for Synopsys DW Memory Card Interface" depends on MMC_DW @@ -748,7 +753,6 @@ config MMC_DW_ZX config MMC_SH_MMCIF tristate "SuperH Internal MMCIF support" - depends on HAS_DMA depends on SUPERH || ARCH_RENESAS || COMPILE_TEST help This selects the MMC Host Interface controller (MMCIF) found in various @@ -756,11 +760,12 @@ config MMC_SH_MMCIF config MMC_JZ4740 - tristate "JZ4740 SD/Multimedia Card Interface support" - depends on MACH_JZ4740 + tristate "Ingenic JZ47xx SD/Multimedia Card Interface support" + depends on MACH_JZ4740 || MACH_JZ4780 help - This selects support for the SD/MMC controller on Ingenic JZ4740 - SoCs. + This selects support for the SD/MMC controller on Ingenic + JZ4740, JZ4750, JZ4770 and JZ4780 SoCs. + If you have a board based on such a SoC and with a SD/MMC slot, say Y or M here. @@ -868,7 +873,6 @@ config MMC_TOSHIBA_PCI config MMC_BCM2835 tristate "Broadcom BCM2835 SDHOST MMC Controller support" depends on ARCH_BCM2835 || COMPILE_TEST - depends on HAS_DMA help This selects the BCM2835 SDHOST MMC controller. If you have a BCM2835 platform with SD or MMC devices, say Y or M here. diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 6aead24879b4..85dc1322c3de 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -49,6 +49,7 @@ thunderx-mmc-objs := cavium.o cavium-thunderx.o obj-$(CONFIG_MMC_CAVIUM_THUNDERX) += thunderx-mmc.o obj-$(CONFIG_MMC_DW) += dw_mmc.o obj-$(CONFIG_MMC_DW_PLTFM) += dw_mmc-pltfm.o +obj-$(CONFIG_MMC_DW_BLUEFIELD) += dw_mmc-bluefield.o obj-$(CONFIG_MMC_DW_EXYNOS) += dw_mmc-exynos.o obj-$(CONFIG_MMC_DW_HI3798CV200) += dw_mmc-hi3798cv200.o obj-$(CONFIG_MMC_DW_K3) += dw_mmc-k3.o diff --git a/drivers/mmc/host/android-goldfish.c b/drivers/mmc/host/android-goldfish.c index 63d27589cd89..294de177632c 100644 --- a/drivers/mmc/host/android-goldfish.c +++ b/drivers/mmc/host/android-goldfish.c @@ -217,8 +217,8 @@ static void goldfish_mmc_xfer_done(struct goldfish_mmc_host *host, * We don't really have DMA, so we need * to copy from our platform driver buffer */ - uint8_t *dest = (uint8_t *)sg_virt(data->sg); - memcpy(dest, host->virt_base, data->sg->length); + sg_copy_to_buffer(data->sg, 1, host->virt_base, + data->sg->length); } host->data->bytes_xfered += data->sg->length; dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_len, @@ -393,8 +393,8 @@ static void goldfish_mmc_prepare_data(struct goldfish_mmc_host *host, * We don't really have DMA, so we need to copy to our * platform driver buffer */ - const uint8_t *src = (uint8_t *)sg_virt(data->sg); - memcpy(host->virt_base, src, data->sg->length); + sg_copy_from_buffer(data->sg, 1, host->virt_base, + data->sg->length); } } diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index e55f3932d580..5aa2c9404e92 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -1967,7 +1967,6 @@ static void atmci_tasklet_func(unsigned long priv) static void atmci_read_data_pio(struct atmel_mci *host) { struct scatterlist *sg = host->sg; - void *buf = sg_virt(sg); unsigned int offset = host->pio_offset; struct mmc_data *data = host->data; u32 value; @@ -1977,7 +1976,7 @@ static void atmci_read_data_pio(struct atmel_mci *host) do { value = atmci_readl(host, ATMCI_RDR); if (likely(offset + 4 <= sg->length)) { - put_unaligned(value, (u32 *)(buf + offset)); + sg_pcopy_to_buffer(sg, 1, &value, sizeof(u32), offset); offset += 4; nbytes += 4; @@ -1990,11 +1989,11 @@ static void atmci_read_data_pio(struct atmel_mci *host) goto done; offset = 0; - buf = sg_virt(sg); } } else { unsigned int remaining = sg->length - offset; - memcpy(buf + offset, &value, remaining); + + sg_pcopy_to_buffer(sg, 1, &value, remaining, offset); nbytes += remaining; flush_dcache_page(sg_page(sg)); @@ -2004,8 +2003,8 @@ static void atmci_read_data_pio(struct atmel_mci *host) goto done; offset = 4 - remaining; - buf = sg_virt(sg); - memcpy(buf, (u8 *)&value + remaining, offset); + sg_pcopy_to_buffer(sg, 1, (u8 *)&value + remaining, + offset, 0); nbytes += offset; } @@ -2035,7 +2034,6 @@ done: static void atmci_write_data_pio(struct atmel_mci *host) { struct scatterlist *sg = host->sg; - void *buf = sg_virt(sg); unsigned int offset = host->pio_offset; struct mmc_data *data = host->data; u32 value; @@ -2044,7 +2042,7 @@ static void atmci_write_data_pio(struct atmel_mci *host) do { if (likely(offset + 4 <= sg->length)) { - value = get_unaligned((u32 *)(buf + offset)); + sg_pcopy_from_buffer(sg, 1, &value, sizeof(u32), offset); atmci_writel(host, ATMCI_TDR, value); offset += 4; @@ -2056,13 +2054,12 @@ static void atmci_write_data_pio(struct atmel_mci *host) goto done; offset = 0; - buf = sg_virt(sg); } } else { unsigned int remaining = sg->length - offset; value = 0; - memcpy(&value, buf + offset, remaining); + sg_pcopy_from_buffer(sg, 1, &value, remaining, offset); nbytes += remaining; host->sg = sg = sg_next(sg); @@ -2073,8 +2070,8 @@ static void atmci_write_data_pio(struct atmel_mci *host) } offset = 4 - remaining; - buf = sg_virt(sg); - memcpy((u8 *)&value + remaining, buf, offset); + sg_pcopy_from_buffer(sg, 1, (u8 *)&value + remaining, + offset, 0); atmci_writel(host, ATMCI_TDR, value); nbytes += offset; } diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c index ed77fbfa4774..9b4be67330dd 100644 --- a/drivers/mmc/host/au1xmmc.c +++ b/drivers/mmc/host/au1xmmc.c @@ -40,6 +40,7 @@ #include <linux/interrupt.h> #include <linux/dma-mapping.h> #include <linux/scatterlist.h> +#include <linux/highmem.h> #include <linux/leds.h> #include <linux/mmc/host.h> #include <linux/slab.h> @@ -405,7 +406,7 @@ static void au1xmmc_send_pio(struct au1xmmc_host *host) /* This is the pointer to the data buffer */ sg = &data->sg[host->pio.index]; - sg_ptr = sg_virt(sg) + host->pio.offset; + sg_ptr = kmap_atomic(sg_page(sg)) + sg->offset + host->pio.offset; /* This is the space left inside the buffer */ sg_len = data->sg[host->pio.index].length - host->pio.offset; @@ -421,11 +422,12 @@ static void au1xmmc_send_pio(struct au1xmmc_host *host) if (!(status & SD_STATUS_TH)) break; - val = *sg_ptr++; + val = sg_ptr[count]; __raw_writel((unsigned long)val, HOST_TXPORT(host)); wmb(); /* drain writebuffer */ } + kunmap_atomic(sg_ptr); host->pio.len -= count; host->pio.offset += count; @@ -462,7 +464,7 @@ static void au1xmmc_receive_pio(struct au1xmmc_host *host) if (host->pio.index < host->dma.len) { sg = &data->sg[host->pio.index]; - sg_ptr = sg_virt(sg) + host->pio.offset; + sg_ptr = kmap_atomic(sg_page(sg)) + sg->offset + host->pio.offset; /* This is the space left inside the buffer */ sg_len = sg_dma_len(&data->sg[host->pio.index]) - host->pio.offset; @@ -501,8 +503,10 @@ static void au1xmmc_receive_pio(struct au1xmmc_host *host) val = __raw_readl(HOST_RXPORT(host)); if (sg_ptr) - *sg_ptr++ = (unsigned char)(val & 0xFF); + sg_ptr[count] = (unsigned char)(val & 0xFF); } + if (sg_ptr) + kunmap_atomic(sg_ptr); host->pio.len -= count; host->pio.offset += count; diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index 8e363174f9d6..9e68c3645e22 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@ -1377,8 +1377,7 @@ static int __exit davinci_mmcsd_remove(struct platform_device *pdev) #ifdef CONFIG_PM static int davinci_mmcsd_suspend(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct mmc_davinci_host *host = platform_get_drvdata(pdev); + struct mmc_davinci_host *host = dev_get_drvdata(dev); writel(0, host->base + DAVINCI_MMCIM); mmc_davinci_reset_ctrl(host, 1); @@ -1389,8 +1388,7 @@ static int davinci_mmcsd_suspend(struct device *dev) static int davinci_mmcsd_resume(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct mmc_davinci_host *host = platform_get_drvdata(pdev); + struct mmc_davinci_host *host = dev_get_drvdata(dev); clk_enable(host->clk); mmc_davinci_reset_ctrl(host, 0); diff --git a/drivers/mmc/host/dw_mmc-bluefield.c b/drivers/mmc/host/dw_mmc-bluefield.c new file mode 100644 index 000000000000..54c3fbb4a391 --- /dev/null +++ b/drivers/mmc/host/dw_mmc-bluefield.c @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 Mellanox Technologies. + * + * 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/bitfield.h> +#include <linux/bitops.h> +#include <linux/mmc/host.h> +#include <linux/mmc/mmc.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> + +#include "dw_mmc.h" +#include "dw_mmc-pltfm.h" + +#define UHS_REG_EXT_SAMPLE_MASK GENMASK(22, 16) +#define UHS_REG_EXT_DRIVE_MASK GENMASK(29, 23) +#define BLUEFIELD_UHS_REG_EXT_SAMPLE 2 +#define BLUEFIELD_UHS_REG_EXT_DRIVE 4 + +static void dw_mci_bluefield_set_ios(struct dw_mci *host, struct mmc_ios *ios) +{ + u32 reg; + + /* Update the Drive and Sample fields in register UHS_REG_EXT. */ + reg = mci_readl(host, UHS_REG_EXT); + reg &= ~UHS_REG_EXT_SAMPLE_MASK; + reg |= FIELD_PREP(UHS_REG_EXT_SAMPLE_MASK, + BLUEFIELD_UHS_REG_EXT_SAMPLE); + reg &= ~UHS_REG_EXT_DRIVE_MASK; + reg |= FIELD_PREP(UHS_REG_EXT_DRIVE_MASK, BLUEFIELD_UHS_REG_EXT_DRIVE); + mci_writel(host, UHS_REG_EXT, reg); +} + +static const struct dw_mci_drv_data bluefield_drv_data = { + .set_ios = dw_mci_bluefield_set_ios +}; + +static const struct of_device_id dw_mci_bluefield_match[] = { + { .compatible = "mellanox,bluefield-dw-mshc", + .data = &bluefield_drv_data }, + {}, +}; +MODULE_DEVICE_TABLE(of, dw_mci_bluefield_match); + +static int dw_mci_bluefield_probe(struct platform_device *pdev) +{ + const struct dw_mci_drv_data *drv_data = NULL; + const struct of_device_id *match; + + if (pdev->dev.of_node) { + match = of_match_node(dw_mci_bluefield_match, + pdev->dev.of_node); + drv_data = match->data; + } + + return dw_mci_pltfm_register(pdev, drv_data); +} + +static struct platform_driver dw_mci_bluefield_pltfm_driver = { + .probe = dw_mci_bluefield_probe, + .remove = dw_mci_pltfm_remove, + .driver = { + .name = "dwmmc_bluefield", + .of_match_table = dw_mci_bluefield_match, + .pm = &dw_mci_pltfm_pmops, + }, +}; + +module_platform_driver(dw_mci_bluefield_pltfm_driver); + +MODULE_DESCRIPTION("BlueField DW Multimedia Card driver"); +MODULE_AUTHOR("Mellanox Technologies"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c index 40d7de2eea12..8c86a800a8fd 100644 --- a/drivers/mmc/host/dw_mmc-rockchip.c +++ b/drivers/mmc/host/dw_mmc-rockchip.c @@ -44,9 +44,8 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios) * bus_hz = cclkin / RK3288_CLKGEN_DIV * ios->clock = (div == 0) ? bus_hz : (bus_hz / (2 * div)) * - * Note: div can only be 0 or 1 - * if DDR50 8bit mode(only emmc work in 8bit mode), - * div must be set 1 + * Note: div can only be 0 or 1, but div must be set to 1 for eMMC + * DDR52 8-bit mode. */ if (ios->bus_width == MMC_BUS_WIDTH_8 && ios->timing == MMC_TIMING_MMC_DDR52) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 29a1afa81f66..623f4d27fa01 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1230,6 +1230,8 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit) if (host->state == STATE_WAITING_CMD11_DONE) sdmmc_cmd_bits |= SDMMC_CMD_VOLT_SWITCH; + slot->mmc->actual_clock = 0; + if (!clock) { mci_writel(host, CLKENA, 0); mci_send_cmd(slot, sdmmc_cmd_bits, 0); @@ -1288,6 +1290,8 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit) /* keep the last clock value that was requested from core */ slot->__clk_old = clock; + slot->mmc->actual_clock = div ? ((host->bus_hz / div) >> 1) : + host->bus_hz; } host->current_speed = clock; diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c index a0168e9e4fce..993386c9ea50 100644 --- a/drivers/mmc/host/jz4740_mmc.c +++ b/drivers/mmc/host/jz4740_mmc.c @@ -1,5 +1,7 @@ /* * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de> + * Copyright (C) 2013, Imagination Technologies + * * JZ4740 SD/MMC controller driver * * This program is free software; you can redistribute it and/or modify it @@ -13,24 +15,25 @@ * */ -#include <linux/mmc/host.h> -#include <linux/mmc/slot-gpio.h> +#include <linux/bitops.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/dmaengine.h> +#include <linux/dma-mapping.h> #include <linux/err.h> +#include <linux/gpio.h> +#include <linux/interrupt.h> #include <linux/io.h> #include <linux/irq.h> -#include <linux/interrupt.h> +#include <linux/mmc/host.h> +#include <linux/mmc/slot-gpio.h> #include <linux/module.h> +#include <linux/of_device.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> -#include <linux/delay.h> #include <linux/scatterlist.h> -#include <linux/clk.h> -#include <linux/bitops.h> -#include <linux/gpio.h> #include <asm/cacheflush.h> -#include <linux/dma-mapping.h> -#include <linux/dmaengine.h> #include <asm/mach-jz4740/dma.h> #include <asm/mach-jz4740/jz4740_mmc.h> @@ -51,6 +54,7 @@ #define JZ_REG_MMC_RESP_FIFO 0x34 #define JZ_REG_MMC_RXFIFO 0x38 #define JZ_REG_MMC_TXFIFO 0x3C +#define JZ_REG_MMC_DMAC 0x44 #define JZ_MMC_STRPCL_EXIT_MULTIPLE BIT(7) #define JZ_MMC_STRPCL_EXIT_TRANSFER BIT(6) @@ -104,9 +108,17 @@ #define JZ_MMC_IRQ_PRG_DONE BIT(1) #define JZ_MMC_IRQ_DATA_TRAN_DONE BIT(0) +#define JZ_MMC_DMAC_DMA_SEL BIT(1) +#define JZ_MMC_DMAC_DMA_EN BIT(0) #define JZ_MMC_CLK_RATE 24000000 +enum jz4740_mmc_version { + JZ_MMC_JZ4740, + JZ_MMC_JZ4750, + JZ_MMC_JZ4780, +}; + enum jz4740_mmc_state { JZ4740_MMC_STATE_READ_RESPONSE, JZ4740_MMC_STATE_TRANSFER_DATA, @@ -125,6 +137,8 @@ struct jz4740_mmc_host { struct jz4740_mmc_platform_data *pdata; struct clk *clk; + enum jz4740_mmc_version version; + int irq; int card_detect_irq; @@ -137,7 +151,7 @@ struct jz4740_mmc_host { uint32_t cmdat; - uint16_t irq_mask; + uint32_t irq_mask; spinlock_t lock; @@ -159,6 +173,32 @@ struct jz4740_mmc_host { #define JZ4740_MMC_FIFO_HALF_SIZE 8 }; +static void jz4740_mmc_write_irq_mask(struct jz4740_mmc_host *host, + uint32_t val) +{ + if (host->version >= JZ_MMC_JZ4750) + return writel(val, host->base + JZ_REG_MMC_IMASK); + else + return writew(val, host->base + JZ_REG_MMC_IMASK); +} + +static void jz4740_mmc_write_irq_reg(struct jz4740_mmc_host *host, + uint32_t val) +{ + if (host->version >= JZ_MMC_JZ4780) + return writel(val, host->base + JZ_REG_MMC_IREG); + else + return writew(val, host->base + JZ_REG_MMC_IREG); +} + +static uint32_t jz4740_mmc_read_irq_reg(struct jz4740_mmc_host *host) +{ + if (host->version >= JZ_MMC_JZ4780) + return readl(host->base + JZ_REG_MMC_IREG); + else + return readw(host->base + JZ_REG_MMC_IREG); +} + /*----------------------------------------------------------------------------*/ /* DMA infrastructure */ @@ -173,31 +213,23 @@ static void jz4740_mmc_release_dma_channels(struct jz4740_mmc_host *host) static int jz4740_mmc_acquire_dma_channels(struct jz4740_mmc_host *host) { - dma_cap_mask_t mask; - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - - host->dma_tx = dma_request_channel(mask, NULL, host); - if (!host->dma_tx) { + host->dma_tx = dma_request_chan(mmc_dev(host->mmc), "tx"); + if (IS_ERR(host->dma_tx)) { dev_err(mmc_dev(host->mmc), "Failed to get dma_tx channel\n"); - return -ENODEV; + return PTR_ERR(host->dma_tx); } - host->dma_rx = dma_request_channel(mask, NULL, host); - if (!host->dma_rx) { + host->dma_rx = dma_request_chan(mmc_dev(host->mmc), "rx"); + if (IS_ERR(host->dma_rx)) { dev_err(mmc_dev(host->mmc), "Failed to get dma_rx channel\n"); - goto free_master_write; + dma_release_channel(host->dma_tx); + return PTR_ERR(host->dma_rx); } /* Initialize DMA pre request cookie */ host->next_data.cookie = 1; return 0; - -free_master_write: - dma_release_channel(host->dma_tx); - return -ENODEV; } static inline struct dma_chan *jz4740_mmc_get_dma_chan(struct jz4740_mmc_host *host, @@ -363,7 +395,7 @@ static void jz4740_mmc_set_irq_enabled(struct jz4740_mmc_host *host, else host->irq_mask |= irq; - writew(host->irq_mask, host->base + JZ_REG_MMC_IMASK); + jz4740_mmc_write_irq_mask(host, host->irq_mask); spin_unlock_irqrestore(&host->lock, flags); } @@ -415,10 +447,10 @@ static unsigned int jz4740_mmc_poll_irq(struct jz4740_mmc_host *host, unsigned int irq) { unsigned int timeout = 0x800; - uint16_t status; + uint32_t status; do { - status = readw(host->base + JZ_REG_MMC_IREG); + status = jz4740_mmc_read_irq_reg(host); } while (!(status & irq) && --timeout); if (timeout == 0) { @@ -518,7 +550,7 @@ static bool jz4740_mmc_read_data(struct jz4740_mmc_host *host, void __iomem *fifo_addr = host->base + JZ_REG_MMC_RXFIFO; uint32_t *buf; uint32_t d; - uint16_t status; + uint32_t status; size_t i, j; unsigned int timeout; @@ -654,8 +686,25 @@ static void jz4740_mmc_send_command(struct jz4740_mmc_host *host, cmdat |= JZ_MMC_CMDAT_DATA_EN; if (cmd->data->flags & MMC_DATA_WRITE) cmdat |= JZ_MMC_CMDAT_WRITE; - if (host->use_dma) - cmdat |= JZ_MMC_CMDAT_DMA_EN; + if (host->use_dma) { + /* + * The 4780's MMC controller has integrated DMA ability + * in addition to being able to use the external DMA + * controller. It moves DMA control bits to a separate + * register. The DMA_SEL bit chooses the external + * controller over the integrated one. Earlier SoCs + * can only use the external controller, and have a + * single DMA enable bit in CMDAT. + */ + if (host->version >= JZ_MMC_JZ4780) { + writel(JZ_MMC_DMAC_DMA_EN | JZ_MMC_DMAC_DMA_SEL, + host->base + JZ_REG_MMC_DMAC); + } else { + cmdat |= JZ_MMC_CMDAT_DMA_EN; + } + } else if (host->version >= JZ_MMC_JZ4780) { + writel(0, host->base + JZ_REG_MMC_DMAC); + } writew(cmd->data->blksz, host->base + JZ_REG_MMC_BLKLEN); writew(cmd->data->blocks, host->base + JZ_REG_MMC_NOB); @@ -736,7 +785,7 @@ static irqreturn_t jz_mmc_irq_worker(int irq, void *devid) host->state = JZ4740_MMC_STATE_SEND_STOP; break; } - writew(JZ_MMC_IRQ_DATA_TRAN_DONE, host->base + JZ_REG_MMC_IREG); + jz4740_mmc_write_irq_reg(host, JZ_MMC_IRQ_DATA_TRAN_DONE); case JZ4740_MMC_STATE_SEND_STOP: if (!req->stop) @@ -766,9 +815,10 @@ static irqreturn_t jz_mmc_irq(int irq, void *devid) { struct jz4740_mmc_host *host = devid; struct mmc_command *cmd = host->cmd; - uint16_t irq_reg, status, tmp; + uint32_t irq_reg, status, tmp; - irq_reg = readw(host->base + JZ_REG_MMC_IREG); + status = readl(host->base + JZ_REG_MMC_STATUS); + irq_reg = jz4740_mmc_read_irq_reg(host); tmp = irq_reg; irq_reg &= ~host->irq_mask; @@ -777,10 +827,10 @@ static irqreturn_t jz_mmc_irq(int irq, void *devid) JZ_MMC_IRQ_PRG_DONE | JZ_MMC_IRQ_DATA_TRAN_DONE); if (tmp != irq_reg) - writew(tmp & ~irq_reg, host->base + JZ_REG_MMC_IREG); + jz4740_mmc_write_irq_reg(host, tmp & ~irq_reg); if (irq_reg & JZ_MMC_IRQ_SDIO) { - writew(JZ_MMC_IRQ_SDIO, host->base + JZ_REG_MMC_IREG); + jz4740_mmc_write_irq_reg(host, JZ_MMC_IRQ_SDIO); mmc_signal_sdio_irq(host->mmc); irq_reg &= ~JZ_MMC_IRQ_SDIO; } @@ -789,8 +839,6 @@ static irqreturn_t jz_mmc_irq(int irq, void *devid) if (test_and_clear_bit(0, &host->waiting)) { del_timer(&host->timeout_timer); - status = readl(host->base + JZ_REG_MMC_STATUS); - if (status & JZ_MMC_STATUS_TIMEOUT_RES) { cmd->error = -ETIMEDOUT; } else if (status & JZ_MMC_STATUS_CRC_RES_ERR) { @@ -803,7 +851,7 @@ static irqreturn_t jz_mmc_irq(int irq, void *devid) } jz4740_mmc_set_irq_enabled(host, irq_reg, false); - writew(irq_reg, host->base + JZ_REG_MMC_IREG); + jz4740_mmc_write_irq_reg(host, irq_reg); return IRQ_WAKE_THREAD; } @@ -818,7 +866,7 @@ static int jz4740_mmc_set_clock_rate(struct jz4740_mmc_host *host, int rate) int real_rate; jz4740_mmc_clock_disable(host); - clk_set_rate(host->clk, JZ_MMC_CLK_RATE); + clk_set_rate(host->clk, host->mmc->f_max); real_rate = clk_get_rate(host->clk); @@ -837,9 +885,7 @@ static void jz4740_mmc_request(struct mmc_host *mmc, struct mmc_request *req) host->req = req; - writew(0xffff, host->base + JZ_REG_MMC_IREG); - - writew(JZ_MMC_IRQ_END_CMD_RES, host->base + JZ_REG_MMC_IREG); + jz4740_mmc_write_irq_reg(host, ~0); jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_END_CMD_RES, true); host->state = JZ4740_MMC_STATE_READ_RESPONSE; @@ -857,7 +903,7 @@ static void jz4740_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) switch (ios->power_mode) { case MMC_POWER_UP: jz4740_mmc_reset(host); - if (gpio_is_valid(host->pdata->gpio_power)) + if (host->pdata && gpio_is_valid(host->pdata->gpio_power)) gpio_set_value(host->pdata->gpio_power, !host->pdata->power_active_low); host->cmdat |= JZ_MMC_CMDAT_INIT; @@ -866,7 +912,7 @@ static void jz4740_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) case MMC_POWER_ON: break; default: - if (gpio_is_valid(host->pdata->gpio_power)) + if (host->pdata && gpio_is_valid(host->pdata->gpio_power)) gpio_set_value(host->pdata->gpio_power, host->pdata->power_active_low); clk_disable_unprepare(host->clk); @@ -926,7 +972,7 @@ static int jz4740_mmc_request_gpio(struct device *dev, int gpio, static int jz4740_mmc_request_gpios(struct mmc_host *mmc, struct platform_device *pdev) { - struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data; + struct jz4740_mmc_platform_data *pdata = dev_get_platdata(&pdev->dev); int ret = 0; if (!pdata) @@ -955,7 +1001,7 @@ static int jz4740_mmc_request_gpios(struct mmc_host *mmc, static void jz4740_mmc_free_gpios(struct platform_device *pdev) { - struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data; + struct jz4740_mmc_platform_data *pdata = dev_get_platdata(&pdev->dev); if (!pdata) return; @@ -964,14 +1010,22 @@ static void jz4740_mmc_free_gpios(struct platform_device *pdev) gpio_free(pdata->gpio_power); } +static const struct of_device_id jz4740_mmc_of_match[] = { + { .compatible = "ingenic,jz4740-mmc", .data = (void *) JZ_MMC_JZ4740 }, + { .compatible = "ingenic,jz4780-mmc", .data = (void *) JZ_MMC_JZ4780 }, + {}, +}; +MODULE_DEVICE_TABLE(of, jz4740_mmc_of_match); + static int jz4740_mmc_probe(struct platform_device* pdev) { int ret; struct mmc_host *mmc; struct jz4740_mmc_host *host; + const struct of_device_id *match; struct jz4740_mmc_platform_data *pdata; - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); mmc = mmc_alloc_host(sizeof(struct jz4740_mmc_host), &pdev->dev); if (!mmc) { @@ -982,6 +1036,27 @@ static int jz4740_mmc_probe(struct platform_device* pdev) host = mmc_priv(mmc); host->pdata = pdata; + match = of_match_device(jz4740_mmc_of_match, &pdev->dev); + if (match) { + host->version = (enum jz4740_mmc_version)match->data; + ret = mmc_of_parse(mmc); + if (ret) { + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, + "could not parse of data: %d\n", ret); + goto err_free_host; + } + } else { + /* JZ4740 should be the only one using legacy probe */ + host->version = JZ_MMC_JZ4740; + mmc->caps |= MMC_CAP_SDIO_IRQ; + if (!(pdata && pdata->data_1bit)) + mmc->caps |= MMC_CAP_4_BIT_DATA; + ret = jz4740_mmc_request_gpios(mmc, pdev); + if (ret) + goto err_free_host; + } + host->irq = platform_get_irq(pdev, 0); if (host->irq < 0) { ret = host->irq; @@ -1004,16 +1079,11 @@ static int jz4740_mmc_probe(struct platform_device* pdev) goto err_free_host; } - ret = jz4740_mmc_request_gpios(mmc, pdev); - if (ret) - goto err_release_dma; - mmc->ops = &jz4740_mmc_ops; - mmc->f_min = JZ_MMC_CLK_RATE / 128; - mmc->f_max = JZ_MMC_CLK_RATE; + if (!mmc->f_max) + mmc->f_max = JZ_MMC_CLK_RATE; + mmc->f_min = mmc->f_max / 128; mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; - mmc->caps = (pdata && pdata->data_1bit) ? 0 : MMC_CAP_4_BIT_DATA; - mmc->caps |= MMC_CAP_SDIO_IRQ; mmc->max_blk_size = (1 << 10) - 1; mmc->max_blk_count = (1 << 15) - 1; @@ -1025,7 +1095,9 @@ static int jz4740_mmc_probe(struct platform_device* pdev) host->mmc = mmc; host->pdev = pdev; spin_lock_init(&host->lock); - host->irq_mask = 0xffff; + host->irq_mask = ~0; + + jz4740_mmc_reset(host); ret = request_threaded_irq(host->irq, jz_mmc_irq, jz_mmc_irq_worker, 0, dev_name(&pdev->dev), host); @@ -1034,20 +1106,20 @@ static int jz4740_mmc_probe(struct platform_device* pdev) goto err_free_gpios; } - jz4740_mmc_reset(host); jz4740_mmc_clock_disable(host); timer_setup(&host->timeout_timer, jz4740_mmc_timeout, 0); - host->use_dma = true; - if (host->use_dma && jz4740_mmc_acquire_dma_channels(host) != 0) - host->use_dma = false; + ret = jz4740_mmc_acquire_dma_channels(host); + if (ret == -EPROBE_DEFER) + goto err_free_irq; + host->use_dma = !ret; platform_set_drvdata(pdev, host); ret = mmc_add_host(mmc); if (ret) { dev_err(&pdev->dev, "Failed to add mmc host: %d\n", ret); - goto err_free_irq; + goto err_release_dma; } dev_info(&pdev->dev, "JZ SD/MMC card driver registered\n"); @@ -1057,13 +1129,13 @@ static int jz4740_mmc_probe(struct platform_device* pdev) return 0; +err_release_dma: + if (host->use_dma) + jz4740_mmc_release_dma_channels(host); err_free_irq: free_irq(host->irq, host); err_free_gpios: jz4740_mmc_free_gpios(pdev); -err_release_dma: - if (host->use_dma) - jz4740_mmc_release_dma_channels(host); err_free_host: mmc_free_host(mmc); @@ -1116,6 +1188,7 @@ static struct platform_driver jz4740_mmc_driver = { .remove = jz4740_mmc_remove, .driver = { .name = "jz4740-mmc", + .of_match_table = of_match_ptr(jz4740_mmc_of_match), .pm = JZ4740_MMC_PM_OPS, }, }; diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c index 4f972b879fe6..c201c378537e 100644 --- a/drivers/mmc/host/meson-gx-mmc.c +++ b/drivers/mmc/host/meson-gx-mmc.c @@ -35,6 +35,7 @@ #include <linux/clk.h> #include <linux/clk-provider.h> #include <linux/regulator/consumer.h> +#include <linux/reset.h> #include <linux/interrupt.h> #include <linux/bitfield.h> #include <linux/pinctrl/consumer.h> @@ -47,15 +48,29 @@ #define CLK_CORE_PHASE_MASK GENMASK(9, 8) #define CLK_TX_PHASE_MASK GENMASK(11, 10) #define CLK_RX_PHASE_MASK GENMASK(13, 12) -#define CLK_TX_DELAY_MASK GENMASK(19, 16) -#define CLK_RX_DELAY_MASK GENMASK(23, 20) +#define CLK_V2_TX_DELAY_MASK GENMASK(19, 16) +#define CLK_V2_RX_DELAY_MASK GENMASK(23, 20) +#define CLK_V2_ALWAYS_ON BIT(24) + +#define CLK_V3_TX_DELAY_MASK GENMASK(21, 16) +#define CLK_V3_RX_DELAY_MASK GENMASK(27, 22) +#define CLK_V3_ALWAYS_ON BIT(28) + #define CLK_DELAY_STEP_PS 200 #define CLK_PHASE_STEP 30 #define CLK_PHASE_POINT_NUM (360 / CLK_PHASE_STEP) -#define CLK_ALWAYS_ON BIT(24) + +#define CLK_TX_DELAY_MASK(h) (h->data->tx_delay_mask) +#define CLK_RX_DELAY_MASK(h) (h->data->rx_delay_mask) +#define CLK_ALWAYS_ON(h) (h->data->always_on) #define SD_EMMC_DELAY 0x4 #define SD_EMMC_ADJUST 0x8 + +#define SD_EMMC_DELAY1 0x4 +#define SD_EMMC_DELAY2 0x8 +#define SD_EMMC_V3_ADJUST 0xc + #define SD_EMMC_CALOUT 0x10 #define SD_EMMC_START 0x40 #define START_DESC_INIT BIT(0) @@ -122,6 +137,12 @@ #define MUX_CLK_NUM_PARENTS 2 +struct meson_mmc_data { + unsigned int tx_delay_mask; + unsigned int rx_delay_mask; + unsigned int always_on; +}; + struct sd_emmc_desc { u32 cmd_cfg; u32 cmd_arg; @@ -131,6 +152,7 @@ struct sd_emmc_desc { struct meson_host { struct device *dev; + struct meson_mmc_data *data; struct mmc_host *mmc; struct mmc_command *cmd; @@ -474,7 +496,7 @@ static int meson_mmc_clk_init(struct meson_host *host) /* init SD_EMMC_CLOCK to sane defaults w/min clock rate */ clk_reg = 0; - clk_reg |= CLK_ALWAYS_ON; + clk_reg |= CLK_ALWAYS_ON(host); clk_reg |= CLK_DIV_MASK; writel(clk_reg, host->regs + SD_EMMC_CLOCK); @@ -574,7 +596,7 @@ static int meson_mmc_clk_init(struct meson_host *host) tx->reg = host->regs + SD_EMMC_CLOCK; tx->phase_mask = CLK_TX_PHASE_MASK; - tx->delay_mask = CLK_TX_DELAY_MASK; + tx->delay_mask = CLK_TX_DELAY_MASK(host); tx->delay_step_ps = CLK_DELAY_STEP_PS; tx->hw.init = &init; @@ -597,7 +619,7 @@ static int meson_mmc_clk_init(struct meson_host *host) rx->reg = host->regs + SD_EMMC_CLOCK; rx->phase_mask = CLK_RX_PHASE_MASK; - rx->delay_mask = CLK_RX_DELAY_MASK; + rx->delay_mask = CLK_RX_DELAY_MASK(host); rx->delay_step_ps = CLK_DELAY_STEP_PS; rx->hw.init = &init; @@ -1184,6 +1206,21 @@ static int meson_mmc_probe(struct platform_device *pdev) goto free_host; } + host->data = (struct meson_mmc_data *) + of_device_get_match_data(&pdev->dev); + if (!host->data) { + ret = -EINVAL; + goto free_host; + } + + ret = device_reset_optional(&pdev->dev); + if (ret) { + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "device reset failed: %d\n", ret); + + return ret; + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); host->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(host->regs)) { @@ -1315,11 +1352,24 @@ static int meson_mmc_remove(struct platform_device *pdev) return 0; } +static const struct meson_mmc_data meson_gx_data = { + .tx_delay_mask = CLK_V2_TX_DELAY_MASK, + .rx_delay_mask = CLK_V2_RX_DELAY_MASK, + .always_on = CLK_V2_ALWAYS_ON, +}; + +static const struct meson_mmc_data meson_axg_data = { + .tx_delay_mask = CLK_V3_TX_DELAY_MASK, + .rx_delay_mask = CLK_V3_RX_DELAY_MASK, + .always_on = CLK_V3_ALWAYS_ON, +}; + static const struct of_device_id meson_mmc_of_match[] = { - { .compatible = "amlogic,meson-gx-mmc", }, - { .compatible = "amlogic,meson-gxbb-mmc", }, - { .compatible = "amlogic,meson-gxl-mmc", }, - { .compatible = "amlogic,meson-gxm-mmc", }, + { .compatible = "amlogic,meson-gx-mmc", .data = &meson_gx_data }, + { .compatible = "amlogic,meson-gxbb-mmc", .data = &meson_gx_data }, + { .compatible = "amlogic,meson-gxl-mmc", .data = &meson_gx_data }, + { .compatible = "amlogic,meson-gxm-mmc", .data = &meson_gx_data }, + { .compatible = "amlogic,meson-axg-mmc", .data = &meson_axg_data }, {} }; MODULE_DEVICE_TABLE(of, meson_mmc_of_match); @@ -1335,6 +1385,6 @@ static struct platform_driver meson_mmc_driver = { module_platform_driver(meson_mmc_driver); -MODULE_DESCRIPTION("Amlogic S905*/GX* SD/eMMC driver"); +MODULE_DESCRIPTION("Amlogic S905*/GX*/AXG SD/eMMC driver"); MODULE_AUTHOR("Kevin Hilman <khilman@baylibre.com>"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 70b0df8b9c78..f1849775e47e 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -1253,15 +1253,12 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id) struct sg_mapping_iter *sg_miter = &host->sg_miter; struct variant_data *variant = host->variant; void __iomem *base = host->base; - unsigned long flags; u32 status; status = readl(base + MMCISTATUS); dev_dbg(mmc_dev(host->mmc), "irq1 (pio) %08x\n", status); - local_irq_save(flags); - do { unsigned int remain, len; char *buffer; @@ -1301,8 +1298,6 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id) sg_miter_stop(sg_miter); - local_irq_restore(flags); - /* * If we have less than the fifo 'half-full' threshold to transfer, * trigger a PIO interrupt as soon as any data is available. diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index cb274e822293..04841386b65d 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -19,6 +19,7 @@ #include <linux/ioport.h> #include <linux/irq.h> #include <linux/of_address.h> +#include <linux/of_device.h> #include <linux/of_irq.h> #include <linux/of_gpio.h> #include <linux/pinctrl/consumer.h> @@ -70,6 +71,7 @@ #define SDC_ADV_CFG0 0x64 #define EMMC_IOCON 0x7c #define SDC_ACMD_RESP 0x80 +#define DMA_SA_H4BIT 0x8c #define MSDC_DMA_SA 0x90 #define MSDC_DMA_CTRL 0x98 #define MSDC_DMA_CFG 0x9c @@ -194,6 +196,9 @@ /* SDC_ADV_CFG0 mask */ #define SDC_RX_ENHANCE_EN (0x1 << 20) /* RW */ +/* DMA_SA_H4BIT mask */ +#define DMA_ADDR_HIGH_4BIT (0xf << 0) /* RW */ + /* MSDC_DMA_CTRL mask */ #define MSDC_DMA_CTRL_START (0x1 << 0) /* W */ #define MSDC_DMA_CTRL_STOP (0x1 << 1) /* W */ @@ -227,6 +232,7 @@ #define MSDC_PATCH_BIT2_CFGRESP (0x1 << 15) /* RW */ #define MSDC_PATCH_BIT2_CFGCRCSTS (0x1 << 28) /* RW */ +#define MSDC_PB2_SUPPORT_64G (0x1 << 1) /* RW */ #define MSDC_PB2_RESPWAIT (0x3 << 2) /* RW */ #define MSDC_PB2_RESPSTSENSEL (0x7 << 16) /* RW */ #define MSDC_PB2_CRCSTSENSEL (0x7 << 29) /* RW */ @@ -280,6 +286,8 @@ struct mt_gpdma_desc { #define GPDMA_DESC_BDP (0x1 << 1) #define GPDMA_DESC_CHECKSUM (0xff << 8) /* bit8 ~ bit15 */ #define GPDMA_DESC_INT (0x1 << 16) +#define GPDMA_DESC_NEXT_H4 (0xf << 24) +#define GPDMA_DESC_PTR_H4 (0xf << 28) u32 next; u32 ptr; u32 gpd_data_len; @@ -296,6 +304,8 @@ struct mt_bdma_desc { #define BDMA_DESC_CHECKSUM (0xff << 8) /* bit8 ~ bit15 */ #define BDMA_DESC_BLKPAD (0x1 << 17) #define BDMA_DESC_DWPAD (0x1 << 18) +#define BDMA_DESC_NEXT_H4 (0xf << 24) +#define BDMA_DESC_PTR_H4 (0xf << 28) u32 next; u32 ptr; u32 bd_data_len; @@ -334,6 +344,7 @@ struct mtk_mmc_compatible { bool busy_check; bool stop_clk_fix; bool enhance_rx; + bool support_64g; }; struct msdc_tune_para { @@ -403,6 +414,7 @@ static const struct mtk_mmc_compatible mt8135_compat = { .busy_check = false, .stop_clk_fix = false, .enhance_rx = false, + .support_64g = false, }; static const struct mtk_mmc_compatible mt8173_compat = { @@ -414,6 +426,7 @@ static const struct mtk_mmc_compatible mt8173_compat = { .busy_check = false, .stop_clk_fix = false, .enhance_rx = false, + .support_64g = false, }; static const struct mtk_mmc_compatible mt2701_compat = { @@ -425,6 +438,7 @@ static const struct mtk_mmc_compatible mt2701_compat = { .busy_check = false, .stop_clk_fix = false, .enhance_rx = false, + .support_64g = false, }; static const struct mtk_mmc_compatible mt2712_compat = { @@ -436,6 +450,7 @@ static const struct mtk_mmc_compatible mt2712_compat = { .busy_check = true, .stop_clk_fix = true, .enhance_rx = true, + .support_64g = true, }; static const struct mtk_mmc_compatible mt7622_compat = { @@ -447,6 +462,7 @@ static const struct mtk_mmc_compatible mt7622_compat = { .busy_check = true, .stop_clk_fix = true, .enhance_rx = true, + .support_64g = false, }; static const struct of_device_id msdc_of_ids[] = { @@ -556,7 +572,12 @@ static inline void msdc_dma_setup(struct msdc_host *host, struct msdc_dma *dma, /* init bd */ bd[j].bd_info &= ~BDMA_DESC_BLKPAD; bd[j].bd_info &= ~BDMA_DESC_DWPAD; - bd[j].ptr = (u32)dma_address; + bd[j].ptr = lower_32_bits(dma_address); + if (host->dev_comp->support_64g) { + bd[j].bd_info &= ~BDMA_DESC_PTR_H4; + bd[j].bd_info |= (upper_32_bits(dma_address) & 0xf) + << 28; + } bd[j].bd_data_len &= ~BDMA_DESC_BUFLEN; bd[j].bd_data_len |= (dma_len & BDMA_DESC_BUFLEN); @@ -575,7 +596,10 @@ static inline void msdc_dma_setup(struct msdc_host *host, struct msdc_dma *dma, dma_ctrl &= ~(MSDC_DMA_CTRL_BRUSTSZ | MSDC_DMA_CTRL_MODE); dma_ctrl |= (MSDC_BURST_64B << 12 | 1 << 8); writel_relaxed(dma_ctrl, host->base + MSDC_DMA_CTRL); - writel((u32)dma->gpd_addr, host->base + MSDC_DMA_SA); + if (host->dev_comp->support_64g) + sdr_set_field(host->base + DMA_SA_H4BIT, DMA_ADDR_HIGH_4BIT, + upper_32_bits(dma->gpd_addr) & 0xf); + writel(lower_32_bits(dma->gpd_addr), host->base + MSDC_DMA_SA); } static void msdc_prepare_data(struct msdc_host *host, struct mmc_request *mrq) @@ -1366,6 +1390,9 @@ static void msdc_init_hw(struct msdc_host *host) MSDC_PATCH_BIT2_CFGCRCSTS); } + if (host->dev_comp->support_64g) + sdr_set_bits(host->base + MSDC_PATCH_BIT2, + MSDC_PB2_SUPPORT_64G); if (host->dev_comp->data_tune) { sdr_set_bits(host->base + tune_reg, MSDC_PAD_TUNE_RD_SEL | MSDC_PAD_TUNE_CMD_SEL); @@ -1407,19 +1434,32 @@ static void msdc_init_gpd_bd(struct msdc_host *host, struct msdc_dma *dma) { struct mt_gpdma_desc *gpd = dma->gpd; struct mt_bdma_desc *bd = dma->bd; + dma_addr_t dma_addr; int i; memset(gpd, 0, sizeof(struct mt_gpdma_desc) * 2); + dma_addr = dma->gpd_addr + sizeof(struct mt_gpdma_desc); gpd->gpd_info = GPDMA_DESC_BDP; /* hwo, cs, bd pointer */ - gpd->ptr = (u32)dma->bd_addr; /* physical address */ /* gpd->next is must set for desc DMA * That's why must alloc 2 gpd structure. */ - gpd->next = (u32)dma->gpd_addr + sizeof(struct mt_gpdma_desc); + gpd->next = lower_32_bits(dma_addr); + if (host->dev_comp->support_64g) + gpd->gpd_info |= (upper_32_bits(dma_addr) & 0xf) << 24; + + dma_addr = dma->bd_addr; + gpd->ptr = lower_32_bits(dma->bd_addr); /* physical address */ + if (host->dev_comp->support_64g) + gpd->gpd_info |= (upper_32_bits(dma_addr) & 0xf) << 28; + memset(bd, 0, sizeof(struct mt_bdma_desc) * MAX_BD_NUM); - for (i = 0; i < (MAX_BD_NUM - 1); i++) - bd[i].next = (u32)dma->bd_addr + sizeof(*bd) * (i + 1); + for (i = 0; i < (MAX_BD_NUM - 1); i++) { + dma_addr = dma->bd_addr + sizeof(*bd) * (i + 1); + bd[i].next = lower_32_bits(dma_addr); + if (host->dev_comp->support_64g) + bd[i].bd_info |= (upper_32_bits(dma_addr) & 0xf) << 24; + } } static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) @@ -1820,7 +1860,6 @@ static int msdc_drv_probe(struct platform_device *pdev) struct mmc_host *mmc; struct msdc_host *host; struct resource *res; - const struct of_device_id *of_id; int ret; if (!pdev->dev.of_node) { @@ -1828,9 +1867,6 @@ static int msdc_drv_probe(struct platform_device *pdev) return -EINVAL; } - of_id = of_match_node(msdc_of_ids, pdev->dev.of_node); - if (!of_id) - return -EINVAL; /* Allocate MMC host for this device */ mmc = mmc_alloc_host(sizeof(struct msdc_host), &pdev->dev); if (!mmc) @@ -1899,7 +1935,7 @@ static int msdc_drv_probe(struct platform_device *pdev) msdc_of_property_parse(pdev, host); host->dev = &pdev->dev; - host->dev_comp = of_id->data; + host->dev_comp = of_device_get_match_data(&pdev->dev); host->mmc = mmc; host->src_clk_freq = clk_get_rate(host->src_clk); /* Set host parameters to mmc */ @@ -1916,7 +1952,10 @@ static int msdc_drv_probe(struct platform_device *pdev) mmc->max_blk_size = 2048; mmc->max_req_size = 512 * 1024; mmc->max_blk_count = mmc->max_req_size / 512; - host->dma_mask = DMA_BIT_MASK(32); + if (host->dev_comp->support_64g) + host->dma_mask = DMA_BIT_MASK(36); + else + host->dma_mask = DMA_BIT_MASK(32); mmc_dev(mmc)->dma_mask = &host->dma_mask; host->timeout_clks = 3 * 1048576; diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c index 210247b3d11a..e22bbff89c8d 100644 --- a/drivers/mmc/host/mvsdio.c +++ b/drivers/mmc/host/mvsdio.c @@ -143,6 +143,7 @@ static void mvsd_request(struct mmc_host *mmc, struct mmc_request *mrq) struct mmc_command *cmd = mrq->cmd; u32 cmdreg = 0, xfer = 0, intr = 0; unsigned long flags; + unsigned int timeout; BUG_ON(host->mrq != NULL); host->mrq = mrq; @@ -234,7 +235,8 @@ static void mvsd_request(struct mmc_host *mmc, struct mmc_request *mrq) mvsd_write(MVSD_NOR_INTR_EN, host->intr_en); mvsd_write(MVSD_ERR_INTR_EN, 0xffff); - mod_timer(&host->timer, jiffies + 5 * HZ); + timeout = cmd->busy_timeout ? cmd->busy_timeout : 5000; + mod_timer(&host->timer, jiffies + msecs_to_jiffies(timeout)); spin_unlock_irqrestore(&host->lock, flags); } @@ -755,6 +757,8 @@ static int mvsd_probe(struct platform_device *pdev) if (maxfreq) mmc->f_max = maxfreq; + mmc->caps |= MMC_CAP_ERASE; + spin_lock_init(&host->lock); host->base = devm_ioremap_resource(&pdev->dev, r); diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 5ff8ef7223cc..75f781c11e89 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -21,6 +21,7 @@ #include <linux/init.h> #include <linux/ioport.h> #include <linux/platform_device.h> +#include <linux/highmem.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/blkdev.h> @@ -291,8 +292,10 @@ static void mxcmci_swap_buffers(struct mmc_data *data) struct scatterlist *sg; int i; - for_each_sg(data->sg, sg, data->sg_len, i) - buffer_swap32(sg_virt(sg), sg->length); + for_each_sg(data->sg, sg, data->sg_len, i) { + void *buf = kmap_atomic(sg_page(sg) + sg->offset; + buffer_swap32(buf, sg->length); + kunmap_atomic(buf); } #else static inline void mxcmci_swap_buffers(struct mmc_data *data) {} @@ -609,6 +612,7 @@ static int mxcmci_transfer_data(struct mxcmci_host *host) { struct mmc_data *data = host->req->data; struct scatterlist *sg; + void *buf; int stat, i; host->data = data; @@ -616,14 +620,18 @@ static int mxcmci_transfer_data(struct mxcmci_host *host) if (data->flags & MMC_DATA_READ) { for_each_sg(data->sg, sg, data->sg_len, i) { - stat = mxcmci_pull(host, sg_virt(sg), sg->length); + buf = kmap_atomic(sg_page(sg) + sg->offset); + stat = mxcmci_pull(host, buf, sg->length); + kunmap(buf); if (stat) return stat; host->datasize += sg->length; } } else { for_each_sg(data->sg, sg, data->sg_len, i) { - stat = mxcmci_push(host, sg_virt(sg), sg->length); + buf = kmap_atomic(sg_page(sg) + sg->offset); + stat = mxcmci_push(host, buf, sg->length); + kunmap(buf); if (stat) return stat; host->datasize += sg->length; @@ -1206,7 +1214,8 @@ static int mxcmci_remove(struct platform_device *pdev) return 0; } -static int __maybe_unused mxcmci_suspend(struct device *dev) +#ifdef CONFIG_PM_SLEEP +static int mxcmci_suspend(struct device *dev) { struct mmc_host *mmc = dev_get_drvdata(dev); struct mxcmci_host *host = mmc_priv(mmc); @@ -1216,7 +1225,7 @@ static int __maybe_unused mxcmci_suspend(struct device *dev) return 0; } -static int __maybe_unused mxcmci_resume(struct device *dev) +static int mxcmci_resume(struct device *dev) { struct mmc_host *mmc = dev_get_drvdata(dev); struct mxcmci_host *host = mmc_priv(mmc); @@ -1232,6 +1241,7 @@ static int __maybe_unused mxcmci_resume(struct device *dev) return ret; } +#endif static SIMPLE_DEV_PM_OPS(mxcmci_pm_ops, mxcmci_suspend, mxcmci_resume); diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index 51e01f03fb99..45c015da2e75 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -28,6 +28,7 @@ #include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/mmc/host.h> +#include <linux/mmc/slot-gpio.h> #include <linux/mfd/tmio.h> #include <linux/sh_dma.h> #include <linux/delay.h> @@ -534,6 +535,10 @@ int renesas_sdhi_probe(struct platform_device *pdev, host->multi_io_quirk = renesas_sdhi_multi_io_quirk; host->dma_ops = dma_ops; + /* For some SoC, we disable internal WP. GPIO may override this */ + if (mmc_can_gpio_ro(host->mmc)) + mmc_data->capabilities2 &= ~MMC_CAP2_NO_WRITE_PROTECT; + /* SDR speeds are only available on Gen2+ */ if (mmc_data->flags & TMIO_MMC_MIN_RCAR2) { /* card_busy caused issues on r8a73a4 (pre-Gen2) CD-less SDHI */ diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c index 6af946d16d24..f7f9773d161f 100644 --- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c @@ -87,11 +87,12 @@ static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = { TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2, .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ | MMC_CAP_CMD23, + .capabilities2 = MMC_CAP2_NO_WRITE_PROTECT, .bus_shift = 2, .scc_offset = 0x1000, .taps = rcar_gen3_scc_taps, .taps_num = ARRAY_SIZE(rcar_gen3_scc_taps), - /* Gen3 SDHI DMAC can handle 0xffffffff blk count, but seg = 1 */ + /* DMAC can handle 0xffffffff blk count but only 1 segment */ .max_blk_count = 0xffffffff, .max_segs = 1, }; @@ -157,38 +158,34 @@ renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host, { struct scatterlist *sg = host->sg_ptr; u32 dtran_mode = DTRAN_MODE_BUS_WID_TH | DTRAN_MODE_ADDR_MODE; - enum dma_data_direction dir; - int ret; - /* This DMAC cannot handle if sg_len is not 1 */ - WARN_ON(host->sg_len > 1); + if (!dma_map_sg(&host->pdev->dev, sg, host->sg_len, + mmc_get_dma_dir(data))) + goto force_pio; /* This DMAC cannot handle if buffer is not 8-bytes alignment */ - if (!IS_ALIGNED(sg->offset, 8)) + if (!IS_ALIGNED(sg_dma_address(sg), 8)) { + dma_unmap_sg(&host->pdev->dev, sg, host->sg_len, + mmc_get_dma_dir(data)); goto force_pio; + } if (data->flags & MMC_DATA_READ) { dtran_mode |= DTRAN_MODE_CH_NUM_CH1; - dir = DMA_FROM_DEVICE; if (test_bit(SDHI_INTERNAL_DMAC_ONE_RX_ONLY, &global_flags) && test_and_set_bit(SDHI_INTERNAL_DMAC_RX_IN_USE, &global_flags)) goto force_pio; } else { dtran_mode |= DTRAN_MODE_CH_NUM_CH0; - dir = DMA_TO_DEVICE; } - ret = dma_map_sg(&host->pdev->dev, sg, host->sg_len, dir); - if (ret == 0) - goto force_pio; - renesas_sdhi_internal_dmac_enable_dma(host, true); /* set dma parameters */ renesas_sdhi_internal_dmac_dm_write(host, DM_CM_DTRAN_MODE, dtran_mode); renesas_sdhi_internal_dmac_dm_write(host, DM_DTRAN_ADDR, - sg->dma_address); + sg_dma_address(sg)); return; @@ -272,12 +269,17 @@ static const struct tmio_mmc_dma_ops renesas_sdhi_internal_dmac_dma_ops = { * implementation as others may use a different implementation. */ static const struct soc_device_attribute gen3_soc_whitelist[] = { + /* specific ones */ { .soc_id = "r8a7795", .revision = "ES1.*", .data = (void *)BIT(SDHI_INTERNAL_DMAC_ONE_RX_ONLY) }, - { .soc_id = "r8a7795", .revision = "ES2.0" }, { .soc_id = "r8a7796", .revision = "ES1.0", .data = (void *)BIT(SDHI_INTERNAL_DMAC_ONE_RX_ONLY) }, - { .soc_id = "r8a77995", .revision = "ES1.0" }, + /* generic ones */ + { .soc_id = "r8a7795" }, + { .soc_id = "r8a7796" }, + { .soc_id = "r8a77965" }, + { .soc_id = "r8a77980" }, + { .soc_id = "r8a77995" }, { /* sentinel */ } }; diff --git a/drivers/mmc/host/renesas_sdhi_sys_dmac.c b/drivers/mmc/host/renesas_sdhi_sys_dmac.c index 848e50c1638a..4bb46c489d71 100644 --- a/drivers/mmc/host/renesas_sdhi_sys_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_sys_dmac.c @@ -42,6 +42,7 @@ static const struct renesas_sdhi_of_data of_rz_compatible = { static const struct renesas_sdhi_of_data of_rcar_gen1_compatible = { .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL, .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ, + .capabilities2 = MMC_CAP2_NO_WRITE_PROTECT, }; /* Definitions for sampling clocks */ @@ -61,6 +62,7 @@ static const struct renesas_sdhi_of_data of_rcar_gen2_compatible = { TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2, .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ | MMC_CAP_CMD23, + .capabilities2 = MMC_CAP2_NO_WRITE_PROTECT, .dma_buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES, .dma_rx_offset = 0x2000, .scc_offset = 0x0300, @@ -81,6 +83,7 @@ static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = { TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2, .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ | MMC_CAP_CMD23, + .capabilities2 = MMC_CAP2_NO_WRITE_PROTECT, .bus_shift = 2, .scc_offset = 0x1000, .taps = rcar_gen3_scc_taps, diff --git a/drivers/mmc/host/rtsx_usb_sdmmc.c b/drivers/mmc/host/rtsx_usb_sdmmc.c index 78422079ecfa..9a3ff22dd0fe 100644 --- a/drivers/mmc/host/rtsx_usb_sdmmc.c +++ b/drivers/mmc/host/rtsx_usb_sdmmc.c @@ -26,7 +26,6 @@ #include <linux/mmc/host.h> #include <linux/mmc/mmc.h> #include <linux/mmc/sd.h> -#include <linux/mmc/sdio.h> #include <linux/mmc/card.h> #include <linux/scatterlist.h> #include <linux/pm_runtime.h> @@ -343,7 +342,7 @@ static void sd_send_cmd_get_rsp(struct rtsx_usb_sdmmc *host, } if (rsp_type == SD_RSP_TYPE_R1b) - timeout = 3000; + timeout = cmd->busy_timeout ? cmd->busy_timeout : 3000; if (cmd->opcode == SD_SWITCH_VOLTAGE) { err = rtsx_usb_write_register(ucr, SD_BUS_STAT, @@ -839,17 +838,6 @@ static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq) goto finish_detect_card; } - /* - * Reject SDIO CMDs to speed up card identification - * since unsupported - */ - if (cmd->opcode == SD_IO_SEND_OP_COND || - cmd->opcode == SD_IO_RW_DIRECT || - cmd->opcode == SD_IO_RW_EXTENDED) { - cmd->error = -EINVAL; - goto finish; - } - mutex_lock(&ucr->dev_mutex); mutex_lock(&host->host_mutex); @@ -1332,8 +1320,9 @@ static void rtsx_usb_init_host(struct rtsx_usb_sdmmc *host) mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_BUS_WIDTH_TEST | MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_SDR50 | - MMC_CAP_NEEDS_POLL; - mmc->caps2 = MMC_CAP2_NO_PRESCAN_POWERUP | MMC_CAP2_FULL_PWR_CYCLE; + MMC_CAP_NEEDS_POLL | MMC_CAP_ERASE; + mmc->caps2 = MMC_CAP2_NO_PRESCAN_POWERUP | MMC_CAP2_FULL_PWR_CYCLE | + MMC_CAP2_NO_SDIO; mmc->max_current_330 = 400; mmc->max_current_180 = 800; diff --git a/drivers/mmc/host/sdhci-bcm-kona.c b/drivers/mmc/host/sdhci-bcm-kona.c index 11ca95c60bcf..bdbd4897c0f7 100644 --- a/drivers/mmc/host/sdhci-bcm-kona.c +++ b/drivers/mmc/host/sdhci-bcm-kona.c @@ -284,10 +284,8 @@ static int sdhci_bcm_kona_probe(struct platform_device *pdev) sdhci_bcm_kona_sd_init(host); ret = sdhci_add_host(host); - if (ret) { - dev_err(dev, "Failed sdhci_add_host\n"); + if (ret) goto err_reset; - } /* if device is eMMC, emulate card insert right here */ if (!mmc_card_is_removable(host->mmc)) { diff --git a/drivers/mmc/host/sdhci-cadence.c b/drivers/mmc/host/sdhci-cadence.c index 0f589e26ee63..7a343b87b5e5 100644 --- a/drivers/mmc/host/sdhci-cadence.c +++ b/drivers/mmc/host/sdhci-cadence.c @@ -253,6 +253,7 @@ static int sdhci_cdns_set_tune_val(struct sdhci_host *host, unsigned int val) struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host); void __iomem *reg = priv->hrs_addr + SDHCI_CDNS_HRS06; u32 tmp; + int i, ret; if (WARN_ON(!FIELD_FIT(SDHCI_CDNS_HRS06_TUNE, val))) return -EINVAL; @@ -260,11 +261,24 @@ static int sdhci_cdns_set_tune_val(struct sdhci_host *host, unsigned int val) tmp = readl(reg); tmp &= ~SDHCI_CDNS_HRS06_TUNE; tmp |= FIELD_PREP(SDHCI_CDNS_HRS06_TUNE, val); - tmp |= SDHCI_CDNS_HRS06_TUNE_UP; - writel(tmp, reg); - return readl_poll_timeout(reg, tmp, !(tmp & SDHCI_CDNS_HRS06_TUNE_UP), - 0, 1); + /* + * Workaround for IP errata: + * The IP6116 SD/eMMC PHY design has a timing issue on receive data + * path. Send tune request twice. + */ + for (i = 0; i < 2; i++) { + tmp |= SDHCI_CDNS_HRS06_TUNE_UP; + writel(tmp, reg); + + ret = readl_poll_timeout(reg, tmp, + !(tmp & SDHCI_CDNS_HRS06_TUNE_UP), + 0, 1); + if (ret) + return ret; + } + + return 0; } static int sdhci_cdns_execute_tuning(struct mmc_host *mmc, u32 opcode) diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index cd2b5f643a15..d6aef70d34fa 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -41,6 +41,12 @@ #define ESDHC_VENDOR_SPEC_FRC_SDCLK_ON (1 << 8) #define ESDHC_WTMK_LVL 0x44 #define ESDHC_WTMK_DEFAULT_VAL 0x10401040 +#define ESDHC_WTMK_LVL_RD_WML_MASK 0x000000FF +#define ESDHC_WTMK_LVL_RD_WML_SHIFT 0 +#define ESDHC_WTMK_LVL_WR_WML_MASK 0x00FF0000 +#define ESDHC_WTMK_LVL_WR_WML_SHIFT 16 +#define ESDHC_WTMK_LVL_WML_VAL_DEF 64 +#define ESDHC_WTMK_LVL_WML_VAL_MAX 128 #define ESDHC_MIX_CTRL 0x48 #define ESDHC_MIX_CTRL_DDREN (1 << 3) #define ESDHC_MIX_CTRL_AC23EN (1 << 7) @@ -516,6 +522,7 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) } if (esdhc_is_usdhc(imx_data)) { + u32 wml; u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL); /* Swap AC23 bit */ if (val & SDHCI_TRNS_AUTO_CMD23) { @@ -524,6 +531,21 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) } m = val | (m & ~ESDHC_MIX_CTRL_SDHCI_MASK); writel(m, host->ioaddr + ESDHC_MIX_CTRL); + + /* Set watermark levels for PIO access to maximum value + * (128 words) to accommodate full 512 bytes buffer. + * For DMA access restore the levels to default value. + */ + m = readl(host->ioaddr + ESDHC_WTMK_LVL); + if (val & SDHCI_TRNS_DMA) + wml = ESDHC_WTMK_LVL_WML_VAL_DEF; + else + wml = ESDHC_WTMK_LVL_WML_VAL_MAX; + m &= ~(ESDHC_WTMK_LVL_RD_WML_MASK | + ESDHC_WTMK_LVL_WR_WML_MASK); + m |= (wml << ESDHC_WTMK_LVL_RD_WML_SHIFT) | + (wml << ESDHC_WTMK_LVL_WR_WML_SHIFT); + writel(m, host->ioaddr + ESDHC_WTMK_LVL); } else { /* * Postpone this write, we must do it together with a diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c index 0ef741bc515d..d0e83db42ae5 100644 --- a/drivers/mmc/host/sdhci-iproc.c +++ b/drivers/mmc/host/sdhci-iproc.c @@ -33,6 +33,8 @@ struct sdhci_iproc_host { const struct sdhci_iproc_data *data; u32 shadow_cmd; u32 shadow_blk; + bool is_cmd_shadowed; + bool is_blk_shadowed; }; #define REG_OFFSET_IN_BITS(reg) ((reg) << 3 & 0x18) @@ -48,8 +50,22 @@ static inline u32 sdhci_iproc_readl(struct sdhci_host *host, int reg) static u16 sdhci_iproc_readw(struct sdhci_host *host, int reg) { - u32 val = sdhci_iproc_readl(host, (reg & ~3)); - u16 word = val >> REG_OFFSET_IN_BITS(reg) & 0xffff; + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_iproc_host *iproc_host = sdhci_pltfm_priv(pltfm_host); + u32 val; + u16 word; + + if ((reg == SDHCI_TRANSFER_MODE) && iproc_host->is_cmd_shadowed) { + /* Get the saved transfer mode */ + val = iproc_host->shadow_cmd; + } else if ((reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) && + iproc_host->is_blk_shadowed) { + /* Get the saved block info */ + val = iproc_host->shadow_blk; + } else { + val = sdhci_iproc_readl(host, (reg & ~3)); + } + word = val >> REG_OFFSET_IN_BITS(reg) & 0xffff; return word; } @@ -105,13 +121,15 @@ static void sdhci_iproc_writew(struct sdhci_host *host, u16 val, int reg) if (reg == SDHCI_COMMAND) { /* Write the block now as we are issuing a command */ - if (iproc_host->shadow_blk != 0) { + if (iproc_host->is_blk_shadowed) { sdhci_iproc_writel(host, iproc_host->shadow_blk, SDHCI_BLOCK_SIZE); - iproc_host->shadow_blk = 0; + iproc_host->is_blk_shadowed = false; } oldval = iproc_host->shadow_cmd; - } else if (reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) { + iproc_host->is_cmd_shadowed = false; + } else if ((reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) && + iproc_host->is_blk_shadowed) { /* Block size and count are stored in shadow reg */ oldval = iproc_host->shadow_blk; } else { @@ -123,9 +141,11 @@ static void sdhci_iproc_writew(struct sdhci_host *host, u16 val, int reg) if (reg == SDHCI_TRANSFER_MODE) { /* Save the transfer mode until the command is issued */ iproc_host->shadow_cmd = newval; + iproc_host->is_cmd_shadowed = true; } else if (reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) { /* Save the block info until the command is issued */ iproc_host->shadow_blk = newval; + iproc_host->is_blk_shadowed = true; } else { /* Command or other regular 32-bit write */ sdhci_iproc_writel(host, newval, reg & ~3); @@ -166,7 +186,7 @@ static const struct sdhci_ops sdhci_iproc_32only_ops = { static const struct sdhci_pltfm_data sdhci_iproc_cygnus_pltfm_data = { .quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK, - .quirks2 = SDHCI_QUIRK2_ACMD23_BROKEN, + .quirks2 = SDHCI_QUIRK2_ACMD23_BROKEN | SDHCI_QUIRK2_HOST_OFF_CARD_ON, .ops = &sdhci_iproc_32only_ops, }; @@ -206,7 +226,6 @@ static const struct sdhci_iproc_data iproc_data = { .caps1 = SDHCI_DRIVER_TYPE_C | SDHCI_DRIVER_TYPE_D | SDHCI_SUPPORT_DDR50, - .mmc_caps = MMC_CAP_1_8V_DDR, }; static const struct sdhci_pltfm_data sdhci_bcm2835_pltfm_data = { diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index c283291db705..646bf377ba77 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -21,6 +21,7 @@ #include <linux/pm_runtime.h> #include <linux/slab.h> #include <linux/iopoll.h> +#include <linux/regulator/consumer.h> #include "sdhci-pltfm.h" @@ -77,10 +78,16 @@ #define CORE_HC_MCLK_SEL_DFLT (2 << 8) #define CORE_HC_MCLK_SEL_HS400 (3 << 8) #define CORE_HC_MCLK_SEL_MASK (3 << 8) +#define CORE_IO_PAD_PWR_SWITCH_EN (1 << 15) +#define CORE_IO_PAD_PWR_SWITCH (1 << 16) #define CORE_HC_SELECT_IN_EN BIT(18) #define CORE_HC_SELECT_IN_HS400 (6 << 19) #define CORE_HC_SELECT_IN_MASK (7 << 19) +#define CORE_3_0V_SUPPORT (1 << 25) +#define CORE_1_8V_SUPPORT (1 << 26) +#define CORE_VOLT_SUPPORT (CORE_3_0V_SUPPORT | CORE_1_8V_SUPPORT) + #define CORE_CSR_CDC_CTLR_CFG0 0x130 #define CORE_SW_TRIG_FULL_CALIB BIT(16) #define CORE_HW_AUTOCAL_ENA BIT(17) @@ -148,6 +155,7 @@ struct sdhci_msm_host { u32 curr_io_level; wait_queue_head_t pwr_irq_wait; bool pwr_irq_flag; + u32 caps_0; }; static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host, @@ -1103,8 +1111,8 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); u32 irq_status, irq_ack = 0; int retry = 10; - int pwr_state = 0, io_level = 0; - + u32 pwr_state = 0, io_level = 0; + u32 config; irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS); irq_status &= INT_MASK; @@ -1161,6 +1169,38 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) */ writel_relaxed(irq_ack, msm_host->core_mem + CORE_PWRCTL_CTL); + /* + * If we don't have info regarding the voltage levels supported by + * regulators, don't change the IO PAD PWR SWITCH. + */ + if (msm_host->caps_0 & CORE_VOLT_SUPPORT) { + u32 new_config; + /* + * We should unset IO PAD PWR switch only if the register write + * can set IO lines high and the regulator also switches to 3 V. + * Else, we should keep the IO PAD PWR switch set. + * This is applicable to certain targets where eMMC vccq supply + * is only 1.8V. In such targets, even during REQ_IO_HIGH, the + * IO PAD PWR switch must be kept set to reflect actual + * regulator voltage. This way, during initialization of + * controllers with only 1.8V, we will set the IO PAD bit + * without waiting for a REQ_IO_LOW. + */ + config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC); + new_config = config; + + if ((io_level & REQ_IO_HIGH) && + (msm_host->caps_0 & CORE_3_0V_SUPPORT)) + new_config &= ~CORE_IO_PAD_PWR_SWITCH; + else if ((io_level & REQ_IO_LOW) || + (msm_host->caps_0 & CORE_1_8V_SUPPORT)) + new_config |= CORE_IO_PAD_PWR_SWITCH; + + if (config ^ new_config) + writel_relaxed(new_config, + host->ioaddr + CORE_VENDOR_SPEC); + } + if (pwr_state) msm_host->curr_pwr_state = pwr_state; if (io_level) @@ -1313,6 +1353,45 @@ static void sdhci_msm_writeb(struct sdhci_host *host, u8 val, int reg) sdhci_msm_check_power_status(host, req_type); } +static void sdhci_msm_set_regulator_caps(struct sdhci_msm_host *msm_host) +{ + struct mmc_host *mmc = msm_host->mmc; + struct regulator *supply = mmc->supply.vqmmc; + u32 caps = 0, config; + struct sdhci_host *host = mmc_priv(mmc); + + if (!IS_ERR(mmc->supply.vqmmc)) { + if (regulator_is_supported_voltage(supply, 1700000, 1950000)) + caps |= CORE_1_8V_SUPPORT; + if (regulator_is_supported_voltage(supply, 2700000, 3600000)) + caps |= CORE_3_0V_SUPPORT; + + if (!caps) + pr_warn("%s: 1.8/3V not supported for vqmmc\n", + mmc_hostname(mmc)); + } + + if (caps) { + /* + * Set the PAD_PWR_SWITCH_EN bit so that the PAD_PWR_SWITCH + * bit can be used as required later on. + */ + u32 io_level = msm_host->curr_io_level; + + config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC); + config |= CORE_IO_PAD_PWR_SWITCH_EN; + + if ((io_level & REQ_IO_HIGH) && (caps & CORE_3_0V_SUPPORT)) + config &= ~CORE_IO_PAD_PWR_SWITCH; + else if ((io_level & REQ_IO_LOW) || (caps & CORE_1_8V_SUPPORT)) + config |= CORE_IO_PAD_PWR_SWITCH; + + writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC); + } + msm_host->caps_0 |= caps; + pr_debug("%s: supported caps: 0x%08x\n", mmc_hostname(mmc), caps); +} + static const struct of_device_id sdhci_msm_dt_match[] = { { .compatible = "qcom,sdhci-msm-v4" }, {}, @@ -1333,7 +1412,6 @@ static const struct sdhci_ops sdhci_msm_ops = { static const struct sdhci_pltfm_data sdhci_msm_pdata = { .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION | - SDHCI_QUIRK_NO_CARD_NO_RESET | SDHCI_QUIRK_SINGLE_POWER_WRITE | SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, @@ -1530,6 +1608,7 @@ static int sdhci_msm_probe(struct platform_device *pdev) ret = sdhci_add_host(host); if (ret) goto pm_runtime_disable; + sdhci_msm_set_regulator_caps(msm_host); pm_runtime_mark_last_busy(&pdev->dev); pm_runtime_put_autosuspend(&pdev->dev); diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index c33a5f7393bd..e3332a522a5d 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -290,7 +290,8 @@ static const struct sdhci_pltfm_data sdhci_arasan_pdata = { .ops = &sdhci_arasan_ops, .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | - SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN, + SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN | + SDHCI_QUIRK2_STOP_WITH_TC, }; static u32 sdhci_arasan_cqhci_irq(struct sdhci_host *host, u32 intmask) @@ -359,8 +360,7 @@ static const struct sdhci_pltfm_data sdhci_arasan_cqe_pdata = { */ static int sdhci_arasan_suspend(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct sdhci_host *host = platform_get_drvdata(pdev); + struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); int ret; @@ -403,8 +403,7 @@ static int sdhci_arasan_suspend(struct device *dev) */ static int sdhci_arasan_resume(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct sdhci_host *host = platform_get_drvdata(pdev); + struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); int ret; diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c index 1456abd5eeb9..f3a7c8ece4be 100644 --- a/drivers/mmc/host/sdhci-omap.c +++ b/drivers/mmc/host/sdhci-omap.c @@ -26,6 +26,7 @@ #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> #include <linux/pinctrl/consumer.h> +#include <linux/sys_soc.h> #include "sdhci-pltfm.h" @@ -35,6 +36,7 @@ #define CON_DDR BIT(19) #define CON_CLKEXTFREE BIT(16) #define CON_PADEN BIT(15) +#define CON_CTPL BIT(11) #define CON_INIT BIT(1) #define CON_OD BIT(0) @@ -100,6 +102,7 @@ struct sdhci_omap_data { }; struct sdhci_omap_host { + char *version; void __iomem *base; struct device *dev; struct regulator *pbias; @@ -224,6 +227,23 @@ static void sdhci_omap_conf_bus_power(struct sdhci_omap_host *omap_host, } } +static void sdhci_omap_enable_sdio_irq(struct mmc_host *mmc, int enable) +{ + struct sdhci_host *host = mmc_priv(mmc); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host); + u32 reg; + + reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON); + if (enable) + reg |= (CON_CTPL | CON_CLKEXTFREE); + else + reg &= ~(CON_CTPL | CON_CLKEXTFREE); + sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, reg); + + sdhci_enable_sdio_irq(mmc, enable); +} + static inline void sdhci_omap_set_dll(struct sdhci_omap_host *omap_host, int count) { @@ -713,10 +733,15 @@ static const struct sdhci_pltfm_data sdhci_omap_pdata = { SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC, .quirks2 = SDHCI_QUIRK2_ACMD23_BROKEN | SDHCI_QUIRK2_PRESET_VALUE_BROKEN | - SDHCI_QUIRK2_RSP_136_HAS_CRC, + SDHCI_QUIRK2_RSP_136_HAS_CRC | + SDHCI_QUIRK2_DISABLE_HW_TIMEOUT, .ops = &sdhci_omap_ops, }; +static const struct sdhci_omap_data k2g_data = { + .offset = 0x200, +}; + static const struct sdhci_omap_data dra7_data = { .offset = 0x200, .flags = SDHCI_OMAP_REQUIRE_IODELAY, @@ -724,6 +749,7 @@ static const struct sdhci_omap_data dra7_data = { static const struct of_device_id omap_sdhci_match[] = { { .compatible = "ti,dra7-sdhci", .data = &dra7_data }, + { .compatible = "ti,k2g-sdhci", .data = &k2g_data }, {}, }; MODULE_DEVICE_TABLE(of, omap_sdhci_match); @@ -733,12 +759,21 @@ static struct pinctrl_state u32 *caps, u32 capmask) { struct device *dev = omap_host->dev; + char *version = omap_host->version; struct pinctrl_state *pinctrl_state = ERR_PTR(-ENODEV); + char str[20]; if (!(*caps & capmask)) goto ret; - pinctrl_state = pinctrl_lookup_state(omap_host->pinctrl, mode); + if (version) { + snprintf(str, 20, "%s-%s", mode, version); + pinctrl_state = pinctrl_lookup_state(omap_host->pinctrl, str); + } + + if (IS_ERR(pinctrl_state)) + pinctrl_state = pinctrl_lookup_state(omap_host->pinctrl, mode); + if (IS_ERR(pinctrl_state)) { dev_err(dev, "no pinctrl state for %s mode", mode); *caps &= ~capmask; @@ -807,8 +842,15 @@ static int sdhci_omap_config_iodelay_pinctrl_state(struct sdhci_omap_host state = sdhci_omap_iodelay_pinctrl_state(omap_host, "ddr_1_8v", caps, MMC_CAP_1_8V_DDR); - if (!IS_ERR(state)) + if (!IS_ERR(state)) { pinctrl_state[MMC_TIMING_MMC_DDR52] = state; + } else { + state = sdhci_omap_iodelay_pinctrl_state(omap_host, "ddr_3_3v", + caps, + MMC_CAP_3_3V_DDR); + if (!IS_ERR(state)) + pinctrl_state[MMC_TIMING_MMC_DDR52] = state; + } state = sdhci_omap_iodelay_pinctrl_state(omap_host, "hs", caps, MMC_CAP_SD_HIGHSPEED); @@ -830,6 +872,16 @@ static int sdhci_omap_config_iodelay_pinctrl_state(struct sdhci_omap_host return 0; } +static const struct soc_device_attribute sdhci_omap_soc_devices[] = { + { + .machine = "DRA7[45]*", + .revision = "ES1.[01]", + }, + { + /* sentinel */ + } +}; + static int sdhci_omap_probe(struct platform_device *pdev) { int ret; @@ -841,6 +893,7 @@ static int sdhci_omap_probe(struct platform_device *pdev) struct mmc_host *mmc; const struct of_device_id *match; struct sdhci_omap_data *data; + const struct soc_device_attribute *soc; match = of_match_device(omap_sdhci_match, dev); if (!match) @@ -871,10 +924,22 @@ static int sdhci_omap_probe(struct platform_device *pdev) host->ioaddr += offset; mmc = host->mmc; + sdhci_get_of_property(pdev); ret = mmc_of_parse(mmc); if (ret) goto err_pltfm_free; + soc = soc_device_match(sdhci_omap_soc_devices); + if (soc) { + omap_host->version = "rev11"; + if (!strcmp(dev_name(dev), "4809c000.mmc")) + mmc->f_max = 96000000; + if (!strcmp(dev_name(dev), "480b4000.mmc")) + mmc->f_max = 48000000; + if (!strcmp(dev_name(dev), "480ad000.mmc")) + mmc->f_max = 48000000; + } + pltfm_host->clk = devm_clk_get(dev, "fck"); if (IS_ERR(pltfm_host->clk)) { ret = PTR_ERR(pltfm_host->clk); @@ -916,26 +981,31 @@ static int sdhci_omap_probe(struct platform_device *pdev) goto err_put_sync; } - ret = sdhci_omap_config_iodelay_pinctrl_state(omap_host); - if (ret) - goto err_put_sync; - host->mmc_host_ops.get_ro = mmc_gpio_get_ro; host->mmc_host_ops.start_signal_voltage_switch = sdhci_omap_start_signal_voltage_switch; host->mmc_host_ops.set_ios = sdhci_omap_set_ios; host->mmc_host_ops.card_busy = sdhci_omap_card_busy; host->mmc_host_ops.execute_tuning = sdhci_omap_execute_tuning; + host->mmc_host_ops.enable_sdio_irq = sdhci_omap_enable_sdio_irq; - sdhci_read_caps(host); - host->caps |= SDHCI_CAN_DO_ADMA2; - - ret = sdhci_add_host(host); + ret = sdhci_setup_host(host); if (ret) goto err_put_sync; + ret = sdhci_omap_config_iodelay_pinctrl_state(omap_host); + if (ret) + goto err_cleanup_host; + + ret = __sdhci_add_host(host); + if (ret) + goto err_cleanup_host; + return 0; +err_cleanup_host: + sdhci_cleanup_host(host); + err_put_sync: pm_runtime_put_sync(dev); diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index 78c25ad35fd2..77dd3521daae 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -453,6 +453,7 @@ static const struct sdhci_pci_fixes sdhci_intel_pch_sdio = { enum { INTEL_DSM_FNS = 0, INTEL_DSM_V18_SWITCH = 3, + INTEL_DSM_V33_SWITCH = 4, INTEL_DSM_DRV_STRENGTH = 9, INTEL_DSM_D3_RETUNE = 10, }; @@ -620,17 +621,37 @@ static void intel_hs400_enhanced_strobe(struct mmc_host *mmc, sdhci_writel(host, val, INTEL_HS400_ES_REG); } -static void sdhci_intel_voltage_switch(struct sdhci_host *host) +static int intel_start_signal_voltage_switch(struct mmc_host *mmc, + struct mmc_ios *ios) { + struct device *dev = mmc_dev(mmc); + struct sdhci_host *host = mmc_priv(mmc); struct sdhci_pci_slot *slot = sdhci_priv(host); struct intel_host *intel_host = sdhci_pci_priv(slot); - struct device *dev = &slot->chip->pdev->dev; + unsigned int fn; u32 result = 0; int err; - err = intel_dsm(intel_host, dev, INTEL_DSM_V18_SWITCH, &result); - pr_debug("%s: %s DSM error %d result %u\n", - mmc_hostname(host->mmc), __func__, err, result); + err = sdhci_start_signal_voltage_switch(mmc, ios); + if (err) + return err; + + switch (ios->signal_voltage) { + case MMC_SIGNAL_VOLTAGE_330: + fn = INTEL_DSM_V33_SWITCH; + break; + case MMC_SIGNAL_VOLTAGE_180: + fn = INTEL_DSM_V18_SWITCH; + break; + default: + return 0; + } + + err = intel_dsm(intel_host, dev, fn, &result); + pr_debug("%s: %s DSM fn %u error %d result %u\n", + mmc_hostname(mmc), __func__, fn, err, result); + + return 0; } static const struct sdhci_ops sdhci_intel_byt_ops = { @@ -641,7 +662,6 @@ static const struct sdhci_ops sdhci_intel_byt_ops = { .reset = sdhci_reset, .set_uhs_signaling = sdhci_set_uhs_signaling, .hw_reset = sdhci_pci_hw_reset, - .voltage_switch = sdhci_intel_voltage_switch, }; static const struct sdhci_ops sdhci_intel_glk_ops = { @@ -652,7 +672,6 @@ static const struct sdhci_ops sdhci_intel_glk_ops = { .reset = sdhci_reset, .set_uhs_signaling = sdhci_set_uhs_signaling, .hw_reset = sdhci_pci_hw_reset, - .voltage_switch = sdhci_intel_voltage_switch, .irq = sdhci_cqhci_irq, }; @@ -691,6 +710,7 @@ static void byt_probe_slot(struct sdhci_pci_slot *slot) byt_read_dsm(slot); ops->execute_tuning = intel_execute_tuning; + ops->start_signal_voltage_switch = intel_start_signal_voltage_switch; } static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot) @@ -832,6 +852,10 @@ static int byt_sd_probe_slot(struct sdhci_pci_slot *slot) slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_GLK_SD) slot->host->mmc_host_ops.get_cd = bxt_get_cd; + if (slot->chip->pdev->subsystem_vendor == PCI_VENDOR_ID_NI && + slot->chip->pdev->subsystem_device == PCI_SUBDEVICE_ID_NI_78E3) + slot->host->mmc->caps2 |= MMC_CAP2_AVOID_3_3V; + return 0; } diff --git a/drivers/mmc/host/sdhci-pci.h b/drivers/mmc/host/sdhci-pci.h index 5cbcdc448f98..db9cb54ef700 100644 --- a/drivers/mmc/host/sdhci-pci.h +++ b/drivers/mmc/host/sdhci-pci.h @@ -54,6 +54,7 @@ #define PCI_DEVICE_ID_REALTEK_5250 0x5250 #define PCI_SUBDEVICE_ID_NI_7884 0x7884 +#define PCI_SUBDEVICE_ID_NI_78E3 0x78e3 #define PCI_VENDOR_ID_ARASAN 0x16e6 #define PCI_DEVICE_ID_ARASAN_PHY_EMMC 0x0670 diff --git a/drivers/mmc/host/sdhci-pic32.c b/drivers/mmc/host/sdhci-pic32.c index a6caa49ca25a..a11e6397d4ff 100644 --- a/drivers/mmc/host/sdhci-pic32.c +++ b/drivers/mmc/host/sdhci-pic32.c @@ -200,10 +200,8 @@ static int pic32_sdhci_probe(struct platform_device *pdev) } ret = sdhci_add_host(host); - if (ret) { - dev_err(&pdev->dev, "error adding host\n"); + if (ret) goto err_base_clk; - } dev_info(&pdev->dev, "Successfully added sdhci host\n"); return 0; diff --git a/drivers/mmc/host/sdhci-pxav2.c b/drivers/mmc/host/sdhci-pxav2.c index 8986f9d9cf98..2c3827f54927 100644 --- a/drivers/mmc/host/sdhci-pxav2.c +++ b/drivers/mmc/host/sdhci-pxav2.c @@ -221,10 +221,8 @@ static int sdhci_pxav2_probe(struct platform_device *pdev) host->ops = &pxav2_sdhci_ops; ret = sdhci_add_host(host); - if (ret) { - dev_err(&pdev->dev, "failed to add host\n"); + if (ret) goto disable_clk; - } return 0; diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index a34434166ca7..b8e96f392428 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -472,10 +472,8 @@ static int sdhci_pxav3_probe(struct platform_device *pdev) pm_suspend_ignore_children(&pdev->dev, 1); ret = sdhci_add_host(host); - if (ret) { - dev_err(&pdev->dev, "failed to add host\n"); + if (ret) goto err_add_host; - } if (host->mmc->pm_caps & MMC_PM_WAKE_SDIO_IRQ) device_init_wakeup(&pdev->dev, 1); diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index cda83ccb2702..9ef89d00970e 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -655,10 +655,8 @@ static int sdhci_s3c_probe(struct platform_device *pdev) goto err_req_regs; ret = sdhci_add_host(host); - if (ret) { - dev_err(dev, "sdhci_add_host() failed\n"); + if (ret) goto err_req_regs; - } #ifdef CONFIG_PM if (pdata->cd_type != S3C_SDHCI_CD_INTERNAL) diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c index 14511526a3a8..9247d51f2eed 100644 --- a/drivers/mmc/host/sdhci-spear.c +++ b/drivers/mmc/host/sdhci-spear.c @@ -126,10 +126,8 @@ static int sdhci_probe(struct platform_device *pdev) } ret = sdhci_add_host(host); - if (ret) { - dev_dbg(&pdev->dev, "error adding host\n"); + if (ret) goto disable_clk; - } platform_set_drvdata(pdev, host); diff --git a/drivers/mmc/host/sdhci-st.c b/drivers/mmc/host/sdhci-st.c index c32daed0d418..8f95647195d9 100644 --- a/drivers/mmc/host/sdhci-st.c +++ b/drivers/mmc/host/sdhci-st.c @@ -422,10 +422,8 @@ static int sdhci_st_probe(struct platform_device *pdev) st_mmcss_cconfig(np, host); ret = sdhci_add_host(host); - if (ret) { - dev_err(&pdev->dev, "Failed sdhci_add_host\n"); + if (ret) goto err_out; - } host_version = readw_relaxed((host->ioaddr + SDHCI_HOST_VERSION)); diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index b877c13184c2..970d38f68939 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -231,7 +231,7 @@ static void tegra_sdhci_set_uhs_signaling(struct sdhci_host *host, if (timing == MMC_TIMING_UHS_DDR50) tegra_host->ddr_signaling = true; - return sdhci_set_uhs_signaling(host, timing); + sdhci_set_uhs_signaling(host, timing); } static unsigned int tegra_sdhci_get_max_clock(struct sdhci_host *host) diff --git a/drivers/mmc/host/sdhci-xenon-phy.c b/drivers/mmc/host/sdhci-xenon-phy.c index ec8794335241..a35804b203a7 100644 --- a/drivers/mmc/host/sdhci-xenon-phy.c +++ b/drivers/mmc/host/sdhci-xenon-phy.c @@ -814,15 +814,10 @@ static int xenon_add_phy(struct device_node *np, struct sdhci_host *host, { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); - int i, ret; + int ret; - for (i = 0; i < NR_PHY_TYPES; i++) { - if (!strcmp(phy_name, phy_types[i])) { - priv->phy_type = i; - break; - } - } - if (i == NR_PHY_TYPES) { + priv->phy_type = match_string(phy_types, NR_PHY_TYPES, phy_name); + if (priv->phy_type < 0) { dev_err(mmc_dev(host->mmc), "Unable to determine PHY name %s. Use default eMMC 5.1 PHY\n", phy_name); diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 2ededa7f43df..1c828e0e9905 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -709,29 +709,16 @@ static u32 sdhci_sdma_address(struct sdhci_host *host) return sg_dma_address(host->data->sg); } -static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd) +static unsigned int sdhci_target_timeout(struct sdhci_host *host, + struct mmc_command *cmd, + struct mmc_data *data) { - u8 count; - struct mmc_data *data = cmd->data; - unsigned target_timeout, current_timeout; - - /* - * If the host controller provides us with an incorrect timeout - * value, just skip the check and use 0xE. The hardware may take - * longer to time out, but that's much better than having a too-short - * timeout value. - */ - if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL) - return 0xE; - - /* Unspecified timeout, assume max */ - if (!data && !cmd->busy_timeout) - return 0xE; + unsigned int target_timeout; /* timeout in us */ - if (!data) + if (!data) { target_timeout = cmd->busy_timeout * 1000; - else { + } else { target_timeout = DIV_ROUND_UP(data->timeout_ns, 1000); if (host->clock && data->timeout_clks) { unsigned long long val; @@ -748,6 +735,67 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd) } } + return target_timeout; +} + +static void sdhci_calc_sw_timeout(struct sdhci_host *host, + struct mmc_command *cmd) +{ + struct mmc_data *data = cmd->data; + struct mmc_host *mmc = host->mmc; + struct mmc_ios *ios = &mmc->ios; + unsigned char bus_width = 1 << ios->bus_width; + unsigned int blksz; + unsigned int freq; + u64 target_timeout; + u64 transfer_time; + + target_timeout = sdhci_target_timeout(host, cmd, data); + target_timeout *= NSEC_PER_USEC; + + if (data) { + blksz = data->blksz; + freq = host->mmc->actual_clock ? : host->clock; + transfer_time = (u64)blksz * NSEC_PER_SEC * (8 / bus_width); + do_div(transfer_time, freq); + /* multiply by '2' to account for any unknowns */ + transfer_time = transfer_time * 2; + /* calculate timeout for the entire data */ + host->data_timeout = data->blocks * target_timeout + + transfer_time; + } else { + host->data_timeout = target_timeout; + } + + if (host->data_timeout) + host->data_timeout += MMC_CMD_TRANSFER_TIME; +} + +static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd, + bool *too_big) +{ + u8 count; + struct mmc_data *data = cmd->data; + unsigned target_timeout, current_timeout; + + *too_big = true; + + /* + * If the host controller provides us with an incorrect timeout + * value, just skip the check and use 0xE. The hardware may take + * longer to time out, but that's much better than having a too-short + * timeout value. + */ + if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL) + return 0xE; + + /* Unspecified timeout, assume max */ + if (!data && !cmd->busy_timeout) + return 0xE; + + /* timeout in us */ + target_timeout = sdhci_target_timeout(host, cmd, data); + /* * Figure out needed cycles. * We do this in steps in order to fit inside a 32 bit int. @@ -768,9 +816,12 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd) } if (count >= 0xF) { - DBG("Too large timeout 0x%x requested for CMD%d!\n", - count, cmd->opcode); + if (!(host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT)) + DBG("Too large timeout 0x%x requested for CMD%d!\n", + count, cmd->opcode); count = 0xE; + } else { + *too_big = false; } return count; @@ -790,6 +841,16 @@ static void sdhci_set_transfer_irqs(struct sdhci_host *host) sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); } +static void sdhci_set_data_timeout_irq(struct sdhci_host *host, bool enable) +{ + if (enable) + host->ier |= SDHCI_INT_DATA_TIMEOUT; + else + host->ier &= ~SDHCI_INT_DATA_TIMEOUT; + sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); + sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); +} + static void sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd) { u8 count; @@ -797,7 +858,18 @@ static void sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd) if (host->ops->set_timeout) { host->ops->set_timeout(host, cmd); } else { - count = sdhci_calc_timeout(host, cmd); + bool too_big = false; + + count = sdhci_calc_timeout(host, cmd, &too_big); + + if (too_big && + host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT) { + sdhci_calc_sw_timeout(host, cmd); + sdhci_set_data_timeout_irq(host, false); + } else if (!(host->ier & SDHCI_INT_DATA_TIMEOUT)) { + sdhci_set_data_timeout_irq(host, true); + } + sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL); } } @@ -807,6 +879,8 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) u8 ctrl; struct mmc_data *data = cmd->data; + host->data_timeout = 0; + if (sdhci_data_line_cmd(cmd)) sdhci_set_timeout(host, cmd); @@ -1160,13 +1234,6 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) mdelay(1); } - timeout = jiffies; - if (!cmd->data && cmd->busy_timeout > 9000) - timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ; - else - timeout += 10 * HZ; - sdhci_mod_timer(host, cmd->mrq, timeout); - host->cmd = cmd; if (sdhci_data_line_cmd(cmd)) { WARN_ON(host->data_cmd); @@ -1206,6 +1273,15 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200) flags |= SDHCI_CMD_DATA; + timeout = jiffies; + if (host->data_timeout) + timeout += nsecs_to_jiffies(host->data_timeout); + else if (!cmd->data && cmd->busy_timeout > 9000) + timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ; + else + timeout += 10 * HZ; + sdhci_mod_timer(host, cmd->mrq, timeout); + sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND); } EXPORT_SYMBOL_GPL(sdhci_send_command); @@ -3616,6 +3692,10 @@ int sdhci_setup_host(struct sdhci_host *host) mmc->max_busy_timeout /= host->timeout_clk; } + if (host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT && + !host->ops->get_max_timeout_count) + mmc->max_busy_timeout = 0; + mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23; mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD; @@ -3672,6 +3752,16 @@ int sdhci_setup_host(struct sdhci_host *host) if (host->quirks2 & SDHCI_QUIRK2_NO_1_8_V) { host->caps1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_DDR50); + /* + * The SDHCI controller in a SoC might support HS200/HS400 + * (indicated using mmc-hs200-1_8v/mmc-hs400-1_8v dt property), + * but if the board is modeled such that the IO lines are not + * connected to 1.8v then HS200/HS400 cannot be supported. + * Disable HS200/HS400 if the board does not have 1.8v connected + * to the IO lines. (Applicable for other modes in 1.8v) + */ + mmc->caps2 &= ~(MMC_CAP2_HSX00_1_8V | MMC_CAP2_HS400_ES); + mmc->caps &= ~(MMC_CAP_1_8V_DDR | MMC_CAP_UHS); } /* Any UHS-I mode in caps implies SDR12 and SDR25 support. */ diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index c95b0a4a7594..23966f887da6 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -332,6 +332,14 @@ struct sdhci_adma2_64_desc { /* Allow for a a command request and a data request at the same time */ #define SDHCI_MAX_MRQS 2 +/* + * 48bit command and 136 bit response in 100KHz clock could take upto 2.48ms. + * However since the start time of the command, the time between + * command and response, and the time between response and start of data is + * not known, set the command transfer time to 10ms. + */ +#define MMC_CMD_TRANSFER_TIME (10 * NSEC_PER_MSEC) /* max 10 ms */ + enum sdhci_cookie { COOKIE_UNMAPPED, COOKIE_PRE_MAPPED, /* mapped by sdhci_pre_req() */ @@ -437,6 +445,11 @@ struct sdhci_host { #define SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN (1<<15) /* Controller has CRC in 136 bit Command Response */ #define SDHCI_QUIRK2_RSP_136_HAS_CRC (1<<16) +/* + * Disable HW timeout if the requested timeout is more than the maximum + * obtainable timeout. + */ +#define SDHCI_QUIRK2_DISABLE_HW_TIMEOUT (1<<17) int irq; /* Device IRQ */ void __iomem *ioaddr; /* Mapped address */ @@ -550,6 +563,8 @@ struct sdhci_host { /* Host SDMA buffer boundary. */ u32 sdma_boundary; + u64 data_timeout; + unsigned long private[0] ____cacheline_aligned; }; diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c index 20cfb20418f3..e7472590f2ed 100644 --- a/drivers/mmc/host/sunxi-mmc.c +++ b/drivers/mmc/host/sunxi-mmc.c @@ -13,36 +13,34 @@ * the License, or (at your option) any later version. */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/io.h> -#include <linux/device.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/err.h> - #include <linux/clk.h> #include <linux/clk/sunxi-ng.h> -#include <linux/gpio.h> -#include <linux/platform_device.h> -#include <linux/spinlock.h> -#include <linux/scatterlist.h> +#include <linux/delay.h> +#include <linux/device.h> #include <linux/dma-mapping.h> -#include <linux/slab.h> -#include <linux/reset.h> -#include <linux/regulator/consumer.h> - -#include <linux/of_address.h> -#include <linux/of_gpio.h> -#include <linux/of_platform.h> - +#include <linux/err.h> +#include <linux/gpio.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/mmc/card.h> +#include <linux/mmc/core.h> #include <linux/mmc/host.h> +#include <linux/mmc/mmc.h> #include <linux/mmc/sd.h> #include <linux/mmc/sdio.h> -#include <linux/mmc/mmc.h> -#include <linux/mmc/core.h> -#include <linux/mmc/card.h> #include <linux/mmc/slot-gpio.h> +#include <linux/module.h> +#include <linux/of_address.h> +#include <linux/of_gpio.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/regulator/consumer.h> +#include <linux/reset.h> +#include <linux/scatterlist.h> +#include <linux/slab.h> +#include <linux/spinlock.h> /* register offset definitions */ #define SDXC_REG_GCTRL (0x00) /* SMC Global Control Register */ @@ -322,10 +320,9 @@ static int sunxi_mmc_reset_host(struct sunxi_mmc_host *host) return 0; } -static int sunxi_mmc_init_host(struct mmc_host *mmc) +static int sunxi_mmc_init_host(struct sunxi_mmc_host *host) { u32 rval; - struct sunxi_mmc_host *host = mmc_priv(mmc); if (sunxi_mmc_reset_host(host)) return -EIO; @@ -859,17 +856,48 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host, return 0; } -static void sunxi_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +static void sunxi_mmc_set_bus_width(struct sunxi_mmc_host *host, + unsigned char width) +{ + switch (width) { + case MMC_BUS_WIDTH_1: + mmc_writel(host, REG_WIDTH, SDXC_WIDTH1); + break; + case MMC_BUS_WIDTH_4: + mmc_writel(host, REG_WIDTH, SDXC_WIDTH4); + break; + case MMC_BUS_WIDTH_8: + mmc_writel(host, REG_WIDTH, SDXC_WIDTH8); + break; + } +} + +static void sunxi_mmc_set_clk(struct sunxi_mmc_host *host, struct mmc_ios *ios) { - struct sunxi_mmc_host *host = mmc_priv(mmc); u32 rval; - /* Set the power state */ - switch (ios->power_mode) { - case MMC_POWER_ON: - break; + /* set ddr mode */ + rval = mmc_readl(host, REG_GCTRL); + if (ios->timing == MMC_TIMING_UHS_DDR50 || + ios->timing == MMC_TIMING_MMC_DDR52) + rval |= SDXC_DDR_MODE; + else + rval &= ~SDXC_DDR_MODE; + mmc_writel(host, REG_GCTRL, rval); + + host->ferror = sunxi_mmc_clk_set_rate(host, ios); + /* Android code had a usleep_range(50000, 55000); here */ +} +static void sunxi_mmc_card_power(struct sunxi_mmc_host *host, + struct mmc_ios *ios) +{ + struct mmc_host *mmc = host->mmc; + + switch (ios->power_mode) { case MMC_POWER_UP: + dev_dbg(mmc_dev(mmc), "Powering card up\n"); + if (!IS_ERR(mmc->supply.vmmc)) { host->ferror = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, @@ -887,53 +915,33 @@ static void sunxi_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) } host->vqmmc_enabled = true; } - - host->ferror = sunxi_mmc_init_host(mmc); - if (host->ferror) - return; - - dev_dbg(mmc_dev(mmc), "power on!\n"); break; case MMC_POWER_OFF: - dev_dbg(mmc_dev(mmc), "power off!\n"); - sunxi_mmc_reset_host(host); + dev_dbg(mmc_dev(mmc), "Powering card off\n"); + if (!IS_ERR(mmc->supply.vmmc)) mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); if (!IS_ERR(mmc->supply.vqmmc) && host->vqmmc_enabled) regulator_disable(mmc->supply.vqmmc); + host->vqmmc_enabled = false; break; - } - /* set bus width */ - switch (ios->bus_width) { - case MMC_BUS_WIDTH_1: - mmc_writel(host, REG_WIDTH, SDXC_WIDTH1); - break; - case MMC_BUS_WIDTH_4: - mmc_writel(host, REG_WIDTH, SDXC_WIDTH4); - break; - case MMC_BUS_WIDTH_8: - mmc_writel(host, REG_WIDTH, SDXC_WIDTH8); + default: + dev_dbg(mmc_dev(mmc), "Ignoring unknown card power state\n"); break; } +} - /* set ddr mode */ - rval = mmc_readl(host, REG_GCTRL); - if (ios->timing == MMC_TIMING_UHS_DDR50 || - ios->timing == MMC_TIMING_MMC_DDR52) - rval |= SDXC_DDR_MODE; - else - rval &= ~SDXC_DDR_MODE; - mmc_writel(host, REG_GCTRL, rval); +static void sunxi_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct sunxi_mmc_host *host = mmc_priv(mmc); - /* set up clock */ - if (ios->power_mode) { - host->ferror = sunxi_mmc_clk_set_rate(host, ios); - /* Android code had a usleep_range(50000, 55000); here */ - } + sunxi_mmc_card_power(host, ios); + sunxi_mmc_set_bus_width(host, ios->bus_width); + sunxi_mmc_set_clk(host, ios); } static int sunxi_mmc_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios) @@ -955,6 +963,9 @@ static void sunxi_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) unsigned long flags; u32 imask; + if (enable) + pm_runtime_get_noresume(host->dev); + spin_lock_irqsave(&host->lock, flags); imask = mmc_readl(host, REG_IMASK); @@ -967,6 +978,9 @@ static void sunxi_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) } mmc_writel(host, REG_IMASK, imask); spin_unlock_irqrestore(&host->lock, flags); + + if (!enable) + pm_runtime_put_noidle(host->mmc->parent); } static void sunxi_mmc_hw_reset(struct mmc_host *mmc) @@ -1380,6 +1394,15 @@ static int sunxi_mmc_probe(struct platform_device *pdev) if (ret) goto error_free_dma; + ret = sunxi_mmc_init_host(host); + if (ret) + goto error_free_dma; + + pm_runtime_set_active(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, 50); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_enable(&pdev->dev); + ret = mmc_add_host(mmc); if (ret) goto error_free_dma; @@ -1400,6 +1423,7 @@ static int sunxi_mmc_remove(struct platform_device *pdev) struct sunxi_mmc_host *host = mmc_priv(mmc); mmc_remove_host(mmc); + pm_runtime_force_suspend(&pdev->dev); disable_irq(host->irq); sunxi_mmc_disable(host); dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); @@ -1408,10 +1432,47 @@ static int sunxi_mmc_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM +static int sunxi_mmc_runtime_resume(struct device *dev) +{ + struct mmc_host *mmc = dev_get_drvdata(dev); + struct sunxi_mmc_host *host = mmc_priv(mmc); + int ret; + + ret = sunxi_mmc_enable(host); + if (ret) + return ret; + + sunxi_mmc_init_host(host); + sunxi_mmc_set_bus_width(host, mmc->ios.bus_width); + sunxi_mmc_set_clk(host, &mmc->ios); + + return 0; +} + +static int sunxi_mmc_runtime_suspend(struct device *dev) +{ + struct mmc_host *mmc = dev_get_drvdata(dev); + struct sunxi_mmc_host *host = mmc_priv(mmc); + + sunxi_mmc_reset_host(host); + sunxi_mmc_disable(host); + + return 0; +} +#endif + +static const struct dev_pm_ops sunxi_mmc_pm_ops = { + SET_RUNTIME_PM_OPS(sunxi_mmc_runtime_suspend, + sunxi_mmc_runtime_resume, + NULL) +}; + static struct platform_driver sunxi_mmc_driver = { .driver = { .name = "sunxi-mmc", .of_match_table = of_match_ptr(sunxi_mmc_of_match), + .pm = &sunxi_mmc_pm_ops, }, .probe = sunxi_mmc_probe, .remove = sunxi_mmc_remove, diff --git a/drivers/mmc/host/ushc.c b/drivers/mmc/host/ushc.c index 81dac17064d7..b2b379b10dfa 100644 --- a/drivers/mmc/host/ushc.c +++ b/drivers/mmc/host/ushc.c @@ -300,8 +300,10 @@ static void ushc_request(struct mmc_host *mmc, struct mmc_request *req) pipe = usb_sndbulkpipe(ushc->usb_dev, 2); usb_fill_bulk_urb(ushc->data_urb, ushc->usb_dev, pipe, - sg_virt(data->sg), data->sg->length, + NULL, data->sg->length, data_callback, ushc); + ushc->data_urb->num_sgs = 1; + ushc->data_urb->sg = data->sg; ret = usb_submit_urb(ushc->data_urb, GFP_ATOMIC); if (ret < 0) goto out; diff --git a/drivers/mmc/host/wbsd.c b/drivers/mmc/host/wbsd.c index f4233576153b..1e54bbf13d75 100644 --- a/drivers/mmc/host/wbsd.c +++ b/drivers/mmc/host/wbsd.c @@ -268,43 +268,29 @@ static inline int wbsd_next_sg(struct wbsd_host *host) return host->num_sg; } -static inline char *wbsd_sg_to_buffer(struct wbsd_host *host) +static inline char *wbsd_map_sg(struct wbsd_host *host) { - return sg_virt(host->cur_sg); + return kmap_atomic(sg_page(host->cur_sg)) + host->cur_sg->offset; } static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data) { - unsigned int len, i; - struct scatterlist *sg; - char *dmabuf = host->dma_buffer; - char *sgbuf; - - sg = data->sg; - len = data->sg_len; - - for (i = 0; i < len; i++) { - sgbuf = sg_virt(&sg[i]); - memcpy(dmabuf, sgbuf, sg[i].length); - dmabuf += sg[i].length; - } + size_t len = 0; + int i; + + for (i = 0; i < data->sg_len; i++) + len += data->sg[i].length; + sg_copy_to_buffer(data->sg, data->sg_len, host->dma_buffer, len); } static inline void wbsd_dma_to_sg(struct wbsd_host *host, struct mmc_data *data) { - unsigned int len, i; - struct scatterlist *sg; - char *dmabuf = host->dma_buffer; - char *sgbuf; - - sg = data->sg; - len = data->sg_len; - - for (i = 0; i < len; i++) { - sgbuf = sg_virt(&sg[i]); - memcpy(sgbuf, dmabuf, sg[i].length); - dmabuf += sg[i].length; - } + size_t len = 0; + int i; + + for (i = 0; i < data->sg_len; i++) + len += data->sg[i].length; + sg_copy_from_buffer(data->sg, data->sg_len, host->dma_buffer, len); } /* @@ -418,7 +404,7 @@ static void wbsd_empty_fifo(struct wbsd_host *host) { struct mmc_data *data = host->mrq->cmd->data; char *buffer; - int i, fsr, fifo; + int i, idx, fsr, fifo; /* * Handle excessive data. @@ -426,7 +412,8 @@ static void wbsd_empty_fifo(struct wbsd_host *host) if (host->num_sg == 0) return; - buffer = wbsd_sg_to_buffer(host) + host->offset; + buffer = wbsd_map_sg(host) + host->offset; + idx = 0; /* * Drain the fifo. This has a tendency to loop longer @@ -445,8 +432,7 @@ static void wbsd_empty_fifo(struct wbsd_host *host) fifo = 1; for (i = 0; i < fifo; i++) { - *buffer = inb(host->base + WBSD_DFR); - buffer++; + buffer[idx++] = inb(host->base + WBSD_DFR); host->offset++; host->remain--; @@ -456,16 +442,19 @@ static void wbsd_empty_fifo(struct wbsd_host *host) * End of scatter list entry? */ if (host->remain == 0) { + kunmap_atomic(buffer); /* * Get next entry. Check if last. */ if (!wbsd_next_sg(host)) return; - buffer = wbsd_sg_to_buffer(host); + buffer = wbsd_map_sg(host); + idx = 0; } } } + kunmap_atomic(buffer); /* * This is a very dirty hack to solve a @@ -480,7 +469,7 @@ static void wbsd_fill_fifo(struct wbsd_host *host) { struct mmc_data *data = host->mrq->cmd->data; char *buffer; - int i, fsr, fifo; + int i, idx, fsr, fifo; /* * Check that we aren't being called after the @@ -489,7 +478,8 @@ static void wbsd_fill_fifo(struct wbsd_host *host) if (host->num_sg == 0) return; - buffer = wbsd_sg_to_buffer(host) + host->offset; + buffer = wbsd_map_sg(host) + host->offset; + idx = 0; /* * Fill the fifo. This has a tendency to loop longer @@ -508,8 +498,7 @@ static void wbsd_fill_fifo(struct wbsd_host *host) fifo = 15; for (i = 16; i > fifo; i--) { - outb(*buffer, host->base + WBSD_DFR); - buffer++; + outb(buffer[idx], host->base + WBSD_DFR); host->offset++; host->remain--; @@ -519,16 +508,19 @@ static void wbsd_fill_fifo(struct wbsd_host *host) * End of scatter list entry? */ if (host->remain == 0) { + kunmap_atomic(buffer); /* * Get next entry. Check if last. */ if (!wbsd_next_sg(host)) return; - buffer = wbsd_sg_to_buffer(host); + buffer = wbsd_map_sg(host); + idx = 0; } } } + kunmap_atomic(buffer); /* * The controller stops sending interrupts for diff --git a/drivers/mmc/host/wmt-sdmmc.c b/drivers/mmc/host/wmt-sdmmc.c index fd30ac7da5e5..3ba42f508014 100644 --- a/drivers/mmc/host/wmt-sdmmc.c +++ b/drivers/mmc/host/wmt-sdmmc.c @@ -928,8 +928,7 @@ static int wmt_mci_remove(struct platform_device *pdev) static int wmt_mci_suspend(struct device *dev) { u32 reg_tmp; - struct platform_device *pdev = to_platform_device(dev); - struct mmc_host *mmc = platform_get_drvdata(pdev); + struct mmc_host *mmc = dev_get_drvdata(dev); struct wmt_mci_priv *priv; if (!mmc) @@ -953,8 +952,7 @@ static int wmt_mci_suspend(struct device *dev) static int wmt_mci_resume(struct device *dev) { u32 reg_tmp; - struct platform_device *pdev = to_platform_device(dev); - struct mmc_host *mmc = platform_get_drvdata(pdev); + struct mmc_host *mmc = dev_get_drvdata(dev); struct wmt_mci_priv *priv; if (mmc) { diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig index 6def5445e03e..57b02c4b3f63 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig @@ -81,6 +81,7 @@ config MTD_DATAFLASH_OTP config MTD_M25P80 tristate "Support most SPI Flash chips (AT26DF, M25P, W25X, ...)" depends on SPI_MASTER && MTD_SPI_NOR + select SPI_MEM help This enables access to most modern SPI flash chips, used for program and data storage. Series supported include Atmel AT26DF, diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index a4e18f6aaa33..e84563d2067f 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -24,12 +24,13 @@ #include <linux/mtd/partitions.h> #include <linux/spi/spi.h> +#include <linux/spi/spi-mem.h> #include <linux/spi/flash.h> #include <linux/mtd/spi-nor.h> #define MAX_CMD_SIZE 6 struct m25p { - struct spi_device *spi; + struct spi_mem *spimem; struct spi_nor spi_nor; u8 command[MAX_CMD_SIZE]; }; @@ -37,97 +38,68 @@ struct m25p { static int m25p80_read_reg(struct spi_nor *nor, u8 code, u8 *val, int len) { struct m25p *flash = nor->priv; - struct spi_device *spi = flash->spi; + struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(code, 1), + SPI_MEM_OP_NO_ADDR, + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_IN(len, val, 1)); int ret; - ret = spi_write_then_read(spi, &code, 1, val, len); + ret = spi_mem_exec_op(flash->spimem, &op); if (ret < 0) - dev_err(&spi->dev, "error %d reading %x\n", ret, code); + dev_err(&flash->spimem->spi->dev, "error %d reading %x\n", ret, + code); return ret; } -static void m25p_addr2cmd(struct spi_nor *nor, unsigned int addr, u8 *cmd) -{ - /* opcode is in cmd[0] */ - cmd[1] = addr >> (nor->addr_width * 8 - 8); - cmd[2] = addr >> (nor->addr_width * 8 - 16); - cmd[3] = addr >> (nor->addr_width * 8 - 24); - cmd[4] = addr >> (nor->addr_width * 8 - 32); -} - -static int m25p_cmdsz(struct spi_nor *nor) -{ - return 1 + nor->addr_width; -} - static int m25p80_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len) { struct m25p *flash = nor->priv; - struct spi_device *spi = flash->spi; - - flash->command[0] = opcode; - if (buf) - memcpy(&flash->command[1], buf, len); + struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(opcode, 1), + SPI_MEM_OP_NO_ADDR, + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_OUT(len, buf, 1)); - return spi_write(spi, flash->command, len + 1); + return spi_mem_exec_op(flash->spimem, &op); } static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len, const u_char *buf) { struct m25p *flash = nor->priv; - struct spi_device *spi = flash->spi; - unsigned int inst_nbits, addr_nbits, data_nbits, data_idx; - struct spi_transfer t[3] = {}; - struct spi_message m; - int cmd_sz = m25p_cmdsz(nor); - ssize_t ret; + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 1), + SPI_MEM_OP_ADDR(nor->addr_width, to, 1), + SPI_MEM_OP_DUMMY(0, 1), + SPI_MEM_OP_DATA_OUT(len, buf, 1)); + size_t remaining = len; + int ret; /* get transfer protocols. */ - inst_nbits = spi_nor_get_protocol_inst_nbits(nor->write_proto); - addr_nbits = spi_nor_get_protocol_addr_nbits(nor->write_proto); - data_nbits = spi_nor_get_protocol_data_nbits(nor->write_proto); - - spi_message_init(&m); + op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->write_proto); + op.addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->write_proto); + op.dummy.buswidth = op.addr.buswidth; + op.data.buswidth = spi_nor_get_protocol_data_nbits(nor->write_proto); if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second) - cmd_sz = 1; - - flash->command[0] = nor->program_opcode; - m25p_addr2cmd(nor, to, flash->command); + op.addr.nbytes = 0; - t[0].tx_buf = flash->command; - t[0].tx_nbits = inst_nbits; - t[0].len = cmd_sz; - spi_message_add_tail(&t[0], &m); - - /* split the op code and address bytes into two transfers if needed. */ - data_idx = 1; - if (addr_nbits != inst_nbits) { - t[0].len = 1; + while (remaining) { + op.data.nbytes = remaining < UINT_MAX ? remaining : UINT_MAX; + ret = spi_mem_adjust_op_size(flash->spimem, &op); + if (ret) + return ret; - t[1].tx_buf = &flash->command[1]; - t[1].tx_nbits = addr_nbits; - t[1].len = cmd_sz - 1; - spi_message_add_tail(&t[1], &m); + ret = spi_mem_exec_op(flash->spimem, &op); + if (ret) + return ret; - data_idx = 2; + op.addr.val += op.data.nbytes; + remaining -= op.data.nbytes; + op.data.buf.out += op.data.nbytes; } - t[data_idx].tx_buf = buf; - t[data_idx].tx_nbits = data_nbits; - t[data_idx].len = len; - spi_message_add_tail(&t[data_idx], &m); - - ret = spi_sync(spi, &m); - if (ret) - return ret; - - ret = m.actual_length - cmd_sz; - if (ret < 0) - return -EIO; - return ret; + return len; } /* @@ -138,92 +110,39 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len, u_char *buf) { struct m25p *flash = nor->priv; - struct spi_device *spi = flash->spi; - unsigned int inst_nbits, addr_nbits, data_nbits, data_idx; - struct spi_transfer t[3]; - struct spi_message m; - unsigned int dummy = nor->read_dummy; - ssize_t ret; - int cmd_sz; + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 1), + SPI_MEM_OP_ADDR(nor->addr_width, from, 1), + SPI_MEM_OP_DUMMY(nor->read_dummy, 1), + SPI_MEM_OP_DATA_IN(len, buf, 1)); + size_t remaining = len; + int ret; /* get transfer protocols. */ - inst_nbits = spi_nor_get_protocol_inst_nbits(nor->read_proto); - addr_nbits = spi_nor_get_protocol_addr_nbits(nor->read_proto); - data_nbits = spi_nor_get_protocol_data_nbits(nor->read_proto); + op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->read_proto); + op.addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->read_proto); + op.dummy.buswidth = op.addr.buswidth; + op.data.buswidth = spi_nor_get_protocol_data_nbits(nor->read_proto); /* convert the dummy cycles to the number of bytes */ - dummy = (dummy * addr_nbits) / 8; - - if (spi_flash_read_supported(spi)) { - struct spi_flash_read_message msg; - - memset(&msg, 0, sizeof(msg)); + op.dummy.nbytes = (nor->read_dummy * op.dummy.buswidth) / 8; - msg.buf = buf; - msg.from = from; - msg.len = len; - msg.read_opcode = nor->read_opcode; - msg.addr_width = nor->addr_width; - msg.dummy_bytes = dummy; - msg.opcode_nbits = inst_nbits; - msg.addr_nbits = addr_nbits; - msg.data_nbits = data_nbits; - - ret = spi_flash_read(spi, &msg); - if (ret < 0) + while (remaining) { + op.data.nbytes = remaining < UINT_MAX ? remaining : UINT_MAX; + ret = spi_mem_adjust_op_size(flash->spimem, &op); + if (ret) return ret; - return msg.retlen; - } - spi_message_init(&m); - memset(t, 0, (sizeof t)); - - flash->command[0] = nor->read_opcode; - m25p_addr2cmd(nor, from, flash->command); - - t[0].tx_buf = flash->command; - t[0].tx_nbits = inst_nbits; - t[0].len = m25p_cmdsz(nor) + dummy; - spi_message_add_tail(&t[0], &m); - - /* - * Set all dummy/mode cycle bits to avoid sending some manufacturer - * specific pattern, which might make the memory enter its Continuous - * Read mode by mistake. - * Based on the different mode cycle bit patterns listed and described - * in the JESD216B specification, the 0xff value works for all memories - * and all manufacturers. - */ - cmd_sz = t[0].len; - memset(flash->command + cmd_sz - dummy, 0xff, dummy); - - /* split the op code and address bytes into two transfers if needed. */ - data_idx = 1; - if (addr_nbits != inst_nbits) { - t[0].len = 1; - - t[1].tx_buf = &flash->command[1]; - t[1].tx_nbits = addr_nbits; - t[1].len = cmd_sz - 1; - spi_message_add_tail(&t[1], &m); + ret = spi_mem_exec_op(flash->spimem, &op); + if (ret) + return ret; - data_idx = 2; + op.addr.val += op.data.nbytes; + remaining -= op.data.nbytes; + op.data.buf.in += op.data.nbytes; } - t[data_idx].rx_buf = buf; - t[data_idx].rx_nbits = data_nbits; - t[data_idx].len = min3(len, spi_max_transfer_size(spi), - spi_max_message_size(spi) - cmd_sz); - spi_message_add_tail(&t[data_idx], &m); - - ret = spi_sync(spi, &m); - if (ret) - return ret; - - ret = m.actual_length - cmd_sz; - if (ret < 0) - return -EIO; - return ret; + return len; } /* @@ -231,8 +150,9 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len, * matches what the READ command supports, at least until this driver * understands FAST_READ (for clocks over 25 MHz). */ -static int m25p_probe(struct spi_device *spi) +static int m25p_probe(struct spi_mem *spimem) { + struct spi_device *spi = spimem->spi; struct flash_platform_data *data; struct m25p *flash; struct spi_nor *nor; @@ -244,9 +164,9 @@ static int m25p_probe(struct spi_device *spi) char *flash_name; int ret; - data = dev_get_platdata(&spi->dev); + data = dev_get_platdata(&spimem->spi->dev); - flash = devm_kzalloc(&spi->dev, sizeof(*flash), GFP_KERNEL); + flash = devm_kzalloc(&spimem->spi->dev, sizeof(*flash), GFP_KERNEL); if (!flash) return -ENOMEM; @@ -258,12 +178,12 @@ static int m25p_probe(struct spi_device *spi) nor->write_reg = m25p80_write_reg; nor->read_reg = m25p80_read_reg; - nor->dev = &spi->dev; + nor->dev = &spimem->spi->dev; spi_nor_set_flash_node(nor, spi->dev.of_node); nor->priv = flash; - spi_set_drvdata(spi, flash); - flash->spi = spi; + spi_mem_set_drvdata(spimem, flash); + flash->spimem = spimem; if (spi->mode & SPI_RX_QUAD) { hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4; @@ -303,9 +223,9 @@ static int m25p_probe(struct spi_device *spi) } -static int m25p_remove(struct spi_device *spi) +static int m25p_remove(struct spi_mem *spimem) { - struct m25p *flash = spi_get_drvdata(spi); + struct m25p *flash = spi_mem_get_drvdata(spimem); spi_nor_restore(&flash->spi_nor); @@ -313,9 +233,9 @@ static int m25p_remove(struct spi_device *spi) return mtd_device_unregister(&flash->spi_nor.mtd); } -static void m25p_shutdown(struct spi_device *spi) +static void m25p_shutdown(struct spi_mem *spimem) { - struct m25p *flash = spi_get_drvdata(spi); + struct m25p *flash = spi_mem_get_drvdata(spimem); spi_nor_restore(&flash->spi_nor); } @@ -386,12 +306,14 @@ static const struct of_device_id m25p_of_table[] = { }; MODULE_DEVICE_TABLE(of, m25p_of_table); -static struct spi_driver m25p80_driver = { - .driver = { - .name = "m25p80", - .of_match_table = m25p_of_table, +static struct spi_mem_driver m25p80_driver = { + .spidrv = { + .driver = { + .name = "m25p80", + .of_match_table = m25p_of_table, + }, + .id_table = m25p_ids, }, - .id_table = m25p_ids, .probe = m25p_probe, .remove = m25p_remove, .shutdown = m25p_shutdown, @@ -402,7 +324,7 @@ static struct spi_driver m25p80_driver = { */ }; -module_spi_driver(m25p80_driver); +module_spi_mem_driver(m25p80_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mike Lavender"); diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 16ae4ae8e8f9..29c0bfd74e8a 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -82,7 +82,6 @@ static blk_status_t do_blktrans_request(struct mtd_blktrans_ops *tr, block = blk_rq_pos(req) << 9 >> tr->blkshift; nsect = blk_rq_cur_bytes(req) >> tr->blkshift; - buf = bio_data(req->bio); if (req_op(req) == REQ_OP_FLUSH) { if (tr->flush(dev)) @@ -100,9 +99,14 @@ static blk_status_t do_blktrans_request(struct mtd_blktrans_ops *tr, return BLK_STS_IOERR; return BLK_STS_OK; case REQ_OP_READ: - for (; nsect > 0; nsect--, block++, buf += tr->blksize) - if (tr->readsect(dev, block, buf)) + buf = kmap(bio_page(req->bio)) + bio_offset(req->bio); + for (; nsect > 0; nsect--, block++, buf += tr->blksize) { + if (tr->readsect(dev, block, buf)) { + kunmap(bio_page(req->bio)); return BLK_STS_IOERR; + } + } + kunmap(bio_page(req->bio)); rq_flush_dcache_pages(req); return BLK_STS_OK; case REQ_OP_WRITE: @@ -110,9 +114,14 @@ static blk_status_t do_blktrans_request(struct mtd_blktrans_ops *tr, return BLK_STS_IOERR; rq_flush_dcache_pages(req); - for (; nsect > 0; nsect--, block++, buf += tr->blksize) - if (tr->writesect(dev, block, buf)) + buf = kmap(bio_page(req->bio)) + bio_offset(req->bio); + for (; nsect > 0; nsect--, block++, buf += tr->blksize) { + if (tr->writesect(dev, block, buf)) { + kunmap(bio_page(req->bio)); return BLK_STS_IOERR; + } + } + kunmap(bio_page(req->bio)); return BLK_STS_OK; default: return BLK_STS_IOERR; @@ -418,7 +427,6 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) new->rq->queuedata = new; blk_queue_logical_block_size(new->rq, tr->blksize); - blk_queue_bounce_limit(new->rq, BLK_BOUNCE_HIGH); blk_queue_flag_set(QUEUE_FLAG_NONROT, new->rq); blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, new->rq); diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 807d17d863b3..64a1fcaafd9a 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -1829,18 +1829,6 @@ static int mtd_proc_show(struct seq_file *m, void *v) mutex_unlock(&mtd_table_mutex); return 0; } - -static int mtd_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, mtd_proc_show, NULL); -} - -static const struct file_operations mtd_proc_ops = { - .open = mtd_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; #endif /* CONFIG_PROC_FS */ /*====================================================================*/ @@ -1883,7 +1871,7 @@ static int __init init_mtd(void) goto err_bdi; } - proc_mtd = proc_create("mtd", 0, NULL, &mtd_proc_ops); + proc_mtd = proc_create_single("mtd", 0, NULL, mtd_proc_show); ret = init_mtdchar(); if (ret) diff --git a/drivers/mtd/nand/raw/cafe_nand.c b/drivers/mtd/nand/raw/cafe_nand.c index d8c8c9d1e640..d721f489b38b 100644 --- a/drivers/mtd/nand/raw/cafe_nand.c +++ b/drivers/mtd/nand/raw/cafe_nand.c @@ -394,12 +394,13 @@ static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, for (i=0; i<8; i+=2) { uint32_t tmp = cafe_readl(cafe, NAND_ECC_SYN01 + (i*2)); - syn[i] = cafe->rs->index_of[tmp & 0xfff]; - syn[i+1] = cafe->rs->index_of[(tmp >> 16) & 0xfff]; + + syn[i] = cafe->rs->codec->index_of[tmp & 0xfff]; + syn[i+1] = cafe->rs->codec->index_of[(tmp >> 16) & 0xfff]; } n = decode_rs16(cafe->rs, NULL, NULL, 1367, syn, 0, pos, 0, - pat); + pat); for (i = 0; i < n; i++) { int p = pos[i]; diff --git a/drivers/mtd/nand/raw/diskonchip.c b/drivers/mtd/nand/raw/diskonchip.c index 86a258de0b75..2b7b2b982b77 100644 --- a/drivers/mtd/nand/raw/diskonchip.c +++ b/drivers/mtd/nand/raw/diskonchip.c @@ -66,6 +66,7 @@ struct doc_priv { int curchip; int mh0_page; int mh1_page; + struct rs_control *rs_decoder; struct mtd_info *nextdoc; /* Handle the last stage of initialization (BBT scan, partitioning) */ @@ -123,9 +124,6 @@ MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe /* Number of symbols */ #define NN 1023 -/* the Reed Solomon control structure */ -static struct rs_control *rs_decoder; - /* * The HW decoder in the DoC ASIC's provides us a error syndrome, * which we must convert to a standard syndrome usable by the generic @@ -140,6 +138,7 @@ static int doc_ecc_decode(struct rs_control *rs, uint8_t *data, uint8_t *ecc) int i, j, nerr, errpos[8]; uint8_t parity; uint16_t ds[4], s[5], tmp, errval[8], syn[4]; + struct rs_codec *cd = rs->codec; memset(syn, 0, sizeof(syn)); /* Convert the ecc bytes into words */ @@ -160,15 +159,15 @@ static int doc_ecc_decode(struct rs_control *rs, uint8_t *data, uint8_t *ecc) for (j = 1; j < NROOTS; j++) { if (ds[j] == 0) continue; - tmp = rs->index_of[ds[j]]; + tmp = cd->index_of[ds[j]]; for (i = 0; i < NROOTS; i++) - s[i] ^= rs->alpha_to[rs_modnn(rs, tmp + (FCR + i) * j)]; + s[i] ^= cd->alpha_to[rs_modnn(cd, tmp + (FCR + i) * j)]; } /* Calc syn[i] = s[i] / alpha^(v + i) */ for (i = 0; i < NROOTS; i++) { if (s[i]) - syn[i] = rs_modnn(rs, rs->index_of[s[i]] + (NN - FCR - i)); + syn[i] = rs_modnn(cd, cd->index_of[s[i]] + (NN - FCR - i)); } /* Call the decoder library */ nerr = decode_rs16(rs, NULL, NULL, 1019, syn, 0, errpos, 0, errval); @@ -930,7 +929,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, calc_ecc[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i); } - ret = doc_ecc_decode(rs_decoder, dat, calc_ecc); + ret = doc_ecc_decode(doc->rs_decoder, dat, calc_ecc); if (ret > 0) pr_err("doc200x_correct_data corrected %d errors\n", ret); @@ -1421,10 +1420,10 @@ static inline int __init doc2001plus_init(struct mtd_info *mtd) static int __init doc_probe(unsigned long physadr) { + struct nand_chip *nand = NULL; + struct doc_priv *doc = NULL; unsigned char ChipID; struct mtd_info *mtd; - struct nand_chip *nand; - struct doc_priv *doc; void __iomem *virtadr; unsigned char save_control; unsigned char tmp, tmpb, tmpc; @@ -1561,8 +1560,25 @@ static int __init doc_probe(unsigned long physadr) goto fail; } + + /* + * Allocate a RS codec instance + * + * Symbolsize is 10 (bits) + * Primitve polynomial is x^10+x^3+1 + * First consecutive root is 510 + * Primitve element to generate roots = 1 + * Generator polinomial degree = 4 + */ + doc = (struct doc_priv *) (nand + 1); + doc->rs_decoder = init_rs(10, 0x409, FCR, 1, NROOTS); + if (!doc->rs_decoder) { + pr_err("DiskOnChip: Could not create a RS codec\n"); + ret = -ENOMEM; + goto fail; + } + mtd = nand_to_mtd(nand); - doc = (struct doc_priv *) (nand + 1); nand->bbt_td = (struct nand_bbt_descr *) (doc + 1); nand->bbt_md = nand->bbt_td + 1; @@ -1612,7 +1628,6 @@ static int __init doc_probe(unsigned long physadr) haven't yet added it. This is handled without incident by mtd_device_unregister, as far as I can tell. */ nand_release(mtd); - kfree(nand); goto fail; } @@ -1625,6 +1640,9 @@ static int __init doc_probe(unsigned long physadr) actually a DiskOnChip. */ WriteDOC(save_control, virtadr, DOCControl); fail: + if (doc) + free_rs(doc->rs_decoder); + kfree(nand); iounmap(virtadr); error_ioremap: @@ -1647,6 +1665,7 @@ static void release_nanddoc(void) nand_release(mtd); iounmap(doc->virtadr); release_mem_region(doc->physadr, DOC_IOREMAP_LEN); + free_rs(doc->rs_decoder); kfree(nand); } } @@ -1655,27 +1674,12 @@ static int __init init_nanddoc(void) { int i, ret = 0; - /* We could create the decoder on demand, if memory is a concern. - * This way we have it handy, if an error happens - * - * Symbolsize is 10 (bits) - * Primitve polynomial is x^10+x^3+1 - * first consecutive root is 510 - * primitve element to generate roots = 1 - * generator polinomial degree = 4 - */ - rs_decoder = init_rs(10, 0x409, FCR, 1, NROOTS); - if (!rs_decoder) { - pr_err("DiskOnChip: Could not create a RS decoder\n"); - return -ENOMEM; - } - if (doc_config_location) { pr_info("Using configured DiskOnChip probe address 0x%lx\n", doc_config_location); ret = doc_probe(doc_config_location); if (ret < 0) - goto outerr; + return ret; } else { for (i = 0; (doc_locations[i] != 0xffffffff); i++) { doc_probe(doc_locations[i]); @@ -1686,11 +1690,7 @@ static int __init init_nanddoc(void) if (!doclist) { pr_info("No valid DiskOnChip devices found\n"); ret = -ENODEV; - goto outerr; } - return 0; - outerr: - free_rs(rs_decoder); return ret; } @@ -1698,11 +1698,6 @@ static void __exit cleanup_nanddoc(void) { /* Cleanup the nand/DoC resources */ release_nanddoc(); - - /* Free the reed solomon resources */ - if (rs_decoder) { - free_rs(rs_decoder); - } } module_init(init_nanddoc); diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c index 01059f1a7bca..9f7d83e827c3 100644 --- a/drivers/net/bonding/bond_procfs.c +++ b/drivers/net/bonding/bond_procfs.c @@ -10,7 +10,7 @@ static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos) __acquires(RCU) { - struct bonding *bond = seq->private; + struct bonding *bond = PDE_DATA(file_inode(seq->file)); struct list_head *iter; struct slave *slave; loff_t off = 0; @@ -29,7 +29,7 @@ static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos) static void *bond_info_seq_next(struct seq_file *seq, void *v, loff_t *pos) { - struct bonding *bond = seq->private; + struct bonding *bond = PDE_DATA(file_inode(seq->file)); struct list_head *iter; struct slave *slave; bool found = false; @@ -56,7 +56,7 @@ static void bond_info_seq_stop(struct seq_file *seq, void *v) static void bond_info_show_master(struct seq_file *seq) { - struct bonding *bond = seq->private; + struct bonding *bond = PDE_DATA(file_inode(seq->file)); const struct bond_opt_value *optval; struct slave *curr, *primary; int i; @@ -167,7 +167,7 @@ static void bond_info_show_master(struct seq_file *seq) static void bond_info_show_slave(struct seq_file *seq, const struct slave *slave) { - struct bonding *bond = seq->private; + struct bonding *bond = PDE_DATA(file_inode(seq->file)); seq_printf(seq, "\nSlave Interface: %s\n", slave->dev->name); seq_printf(seq, "MII Status: %s\n", bond_slave_link_status(slave->link)); @@ -257,38 +257,14 @@ static const struct seq_operations bond_info_seq_ops = { .show = bond_info_seq_show, }; -static int bond_info_open(struct inode *inode, struct file *file) -{ - struct seq_file *seq; - int res; - - res = seq_open(file, &bond_info_seq_ops); - if (!res) { - /* recover the pointer buried in proc_dir_entry data */ - seq = file->private_data; - seq->private = PDE_DATA(inode); - } - - return res; -} - -static const struct file_operations bond_info_fops = { - .owner = THIS_MODULE, - .open = bond_info_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - void bond_create_proc_entry(struct bonding *bond) { struct net_device *bond_dev = bond->dev; struct bond_net *bn = net_generic(dev_net(bond_dev), bond_net_id); if (bn->proc_dir) { - bond->proc_entry = proc_create_data(bond_dev->name, - 0444, bn->proc_dir, - &bond_info_fops, bond); + bond->proc_entry = proc_create_seq_data(bond_dev->name, 0444, + bn->proc_dir, &bond_info_seq_ops, bond); if (bond->proc_entry == NULL) netdev_warn(bond_dev, "Cannot create /proc/net/%s/%s\n", DRV_NAME, bond_dev->name); diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 78616787f2a3..3da5fca77cbd 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -1712,6 +1712,18 @@ static const struct b53_chip_data b53_switch_chips[] = { .duplex_reg = B53_DUPLEX_STAT_FE, }, { + .chip_id = BCM5389_DEVICE_ID, + .dev_name = "BCM5389", + .vlans = 4096, + .enabled_ports = 0x1f, + .arl_entries = 4, + .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + }, + { .chip_id = BCM5395_DEVICE_ID, .dev_name = "BCM5395", .vlans = 4096, @@ -2034,6 +2046,7 @@ int b53_switch_detect(struct b53_device *dev) else dev->chip_id = BCM5365_DEVICE_ID; break; + case BCM5389_DEVICE_ID: case BCM5395_DEVICE_ID: case BCM5397_DEVICE_ID: case BCM5398_DEVICE_ID: diff --git a/drivers/net/dsa/b53/b53_mdio.c b/drivers/net/dsa/b53/b53_mdio.c index fa7556f5d4fb..a533a90e3904 100644 --- a/drivers/net/dsa/b53/b53_mdio.c +++ b/drivers/net/dsa/b53/b53_mdio.c @@ -285,6 +285,7 @@ static const struct b53_io_ops b53_mdio_ops = { #define B53_BRCM_OUI_1 0x0143bc00 #define B53_BRCM_OUI_2 0x03625c00 #define B53_BRCM_OUI_3 0x00406000 +#define B53_BRCM_OUI_4 0x01410c00 static int b53_mdio_probe(struct mdio_device *mdiodev) { @@ -311,7 +312,8 @@ static int b53_mdio_probe(struct mdio_device *mdiodev) */ if ((phy_id & 0xfffffc00) != B53_BRCM_OUI_1 && (phy_id & 0xfffffc00) != B53_BRCM_OUI_2 && - (phy_id & 0xfffffc00) != B53_BRCM_OUI_3) { + (phy_id & 0xfffffc00) != B53_BRCM_OUI_3 && + (phy_id & 0xfffffc00) != B53_BRCM_OUI_4) { dev_err(&mdiodev->dev, "Unsupported device: 0x%08x\n", phy_id); return -ENODEV; } @@ -360,6 +362,7 @@ static const struct of_device_id b53_of_match[] = { { .compatible = "brcm,bcm53125" }, { .compatible = "brcm,bcm53128" }, { .compatible = "brcm,bcm5365" }, + { .compatible = "brcm,bcm5389" }, { .compatible = "brcm,bcm5395" }, { .compatible = "brcm,bcm5397" }, { .compatible = "brcm,bcm5398" }, diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h index 1187ebd79287..3b57f47d0e79 100644 --- a/drivers/net/dsa/b53/b53_priv.h +++ b/drivers/net/dsa/b53/b53_priv.h @@ -48,6 +48,7 @@ struct b53_io_ops { enum { BCM5325_DEVICE_ID = 0x25, BCM5365_DEVICE_ID = 0x65, + BCM5389_DEVICE_ID = 0x89, BCM5395_DEVICE_ID = 0x95, BCM5397_DEVICE_ID = 0x97, BCM5398_DEVICE_ID = 0x98, diff --git a/drivers/net/dsa/bcm_sf2_cfp.c b/drivers/net/dsa/bcm_sf2_cfp.c index 23b45da784cb..b89acaee12d4 100644 --- a/drivers/net/dsa/bcm_sf2_cfp.c +++ b/drivers/net/dsa/bcm_sf2_cfp.c @@ -354,10 +354,13 @@ static int bcm_sf2_cfp_ipv4_rule_set(struct bcm_sf2_priv *priv, int port, /* Locate the first rule available */ if (fs->location == RX_CLS_LOC_ANY) rule_index = find_first_zero_bit(priv->cfp.used, - bcm_sf2_cfp_rule_size(priv)); + priv->num_cfp_rules); else rule_index = fs->location; + if (rule_index > bcm_sf2_cfp_rule_size(priv)) + return -ENOSPC; + layout = &udf_tcpip4_layout; /* We only use one UDF slice for now */ slice_num = bcm_sf2_get_slice_number(layout, 0); @@ -562,19 +565,21 @@ static int bcm_sf2_cfp_ipv6_rule_set(struct bcm_sf2_priv *priv, int port, * first half because the HW search is by incrementing addresses. */ if (fs->location == RX_CLS_LOC_ANY) - rule_index[0] = find_first_zero_bit(priv->cfp.used, - bcm_sf2_cfp_rule_size(priv)); + rule_index[1] = find_first_zero_bit(priv->cfp.used, + priv->num_cfp_rules); else - rule_index[0] = fs->location; + rule_index[1] = fs->location; + if (rule_index[1] > bcm_sf2_cfp_rule_size(priv)) + return -ENOSPC; /* Flag it as used (cleared on error path) such that we can immediately * obtain a second one to chain from. */ - set_bit(rule_index[0], priv->cfp.used); + set_bit(rule_index[1], priv->cfp.used); - rule_index[1] = find_first_zero_bit(priv->cfp.used, - bcm_sf2_cfp_rule_size(priv)); - if (rule_index[1] > bcm_sf2_cfp_rule_size(priv)) { + rule_index[0] = find_first_zero_bit(priv->cfp.used, + priv->num_cfp_rules); + if (rule_index[0] > bcm_sf2_cfp_rule_size(priv)) { ret = -ENOSPC; goto out_err; } @@ -712,14 +717,14 @@ static int bcm_sf2_cfp_ipv6_rule_set(struct bcm_sf2_priv *priv, int port, /* Flag the second half rule as being used now, return it as the * location, and flag it as unique while dumping rules */ - set_bit(rule_index[1], priv->cfp.used); + set_bit(rule_index[0], priv->cfp.used); set_bit(rule_index[1], priv->cfp.unique); fs->location = rule_index[1]; return ret; out_err: - clear_bit(rule_index[0], priv->cfp.used); + clear_bit(rule_index[1], priv->cfp.used); return ret; } @@ -785,10 +790,6 @@ static int bcm_sf2_cfp_rule_del_one(struct bcm_sf2_priv *priv, int port, int ret; u32 reg; - /* Refuse deletion of unused rules, and the default reserved rule */ - if (!test_bit(loc, priv->cfp.used) || loc == 0) - return -EINVAL; - /* Indicate which rule we want to read */ bcm_sf2_cfp_rule_addr_set(priv, loc); @@ -826,6 +827,13 @@ static int bcm_sf2_cfp_rule_del(struct bcm_sf2_priv *priv, int port, u32 next_loc = 0; int ret; + /* Refuse deleting unused rules, and those that are not unique since + * that could leave IPv6 rules with one of the chained rule in the + * table. + */ + if (!test_bit(loc, priv->cfp.unique) || loc == 0) + return -EINVAL; + ret = bcm_sf2_cfp_rule_del_one(priv, port, loc, &next_loc); if (ret) return ret; diff --git a/drivers/net/ethernet/3com/3c59x.c b/drivers/net/ethernet/3com/3c59x.c index 36c8950dbd2d..176861bd2252 100644 --- a/drivers/net/ethernet/3com/3c59x.c +++ b/drivers/net/ethernet/3com/3c59x.c @@ -1212,9 +1212,9 @@ static int vortex_probe1(struct device *gendev, void __iomem *ioaddr, int irq, vp->mii.reg_num_mask = 0x1f; /* Makes sure rings are at least 16 byte aligned. */ - vp->rx_ring = pci_alloc_consistent(pdev, sizeof(struct boom_rx_desc) * RX_RING_SIZE + vp->rx_ring = dma_alloc_coherent(gendev, sizeof(struct boom_rx_desc) * RX_RING_SIZE + sizeof(struct boom_tx_desc) * TX_RING_SIZE, - &vp->rx_ring_dma); + &vp->rx_ring_dma, GFP_KERNEL); retval = -ENOMEM; if (!vp->rx_ring) goto free_device; @@ -1476,11 +1476,10 @@ static int vortex_probe1(struct device *gendev, void __iomem *ioaddr, int irq, return 0; free_ring: - pci_free_consistent(pdev, - sizeof(struct boom_rx_desc) * RX_RING_SIZE - + sizeof(struct boom_tx_desc) * TX_RING_SIZE, - vp->rx_ring, - vp->rx_ring_dma); + dma_free_coherent(&pdev->dev, + sizeof(struct boom_rx_desc) * RX_RING_SIZE + + sizeof(struct boom_tx_desc) * TX_RING_SIZE, + vp->rx_ring, vp->rx_ring_dma); free_device: free_netdev(dev); pr_err(PFX "vortex_probe1 fails. Returns %d\n", retval); @@ -1751,9 +1750,9 @@ vortex_open(struct net_device *dev) break; /* Bad news! */ skb_reserve(skb, NET_IP_ALIGN); /* Align IP on 16 byte boundaries */ - dma = pci_map_single(VORTEX_PCI(vp), skb->data, - PKT_BUF_SZ, PCI_DMA_FROMDEVICE); - if (dma_mapping_error(&VORTEX_PCI(vp)->dev, dma)) + dma = dma_map_single(vp->gendev, skb->data, + PKT_BUF_SZ, DMA_FROM_DEVICE); + if (dma_mapping_error(vp->gendev, dma)) break; vp->rx_ring[i].addr = cpu_to_le32(dma); } @@ -2067,9 +2066,9 @@ vortex_start_xmit(struct sk_buff *skb, struct net_device *dev) if (vp->bus_master) { /* Set the bus-master controller to transfer the packet. */ int len = (skb->len + 3) & ~3; - vp->tx_skb_dma = pci_map_single(VORTEX_PCI(vp), skb->data, len, - PCI_DMA_TODEVICE); - if (dma_mapping_error(&VORTEX_PCI(vp)->dev, vp->tx_skb_dma)) { + vp->tx_skb_dma = dma_map_single(vp->gendev, skb->data, len, + DMA_TO_DEVICE); + if (dma_mapping_error(vp->gendev, vp->tx_skb_dma)) { dev_kfree_skb_any(skb); dev->stats.tx_dropped++; return NETDEV_TX_OK; @@ -2168,9 +2167,9 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev) vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded | AddTCPChksum | AddUDPChksum); if (!skb_shinfo(skb)->nr_frags) { - dma_addr = pci_map_single(VORTEX_PCI(vp), skb->data, skb->len, - PCI_DMA_TODEVICE); - if (dma_mapping_error(&VORTEX_PCI(vp)->dev, dma_addr)) + dma_addr = dma_map_single(vp->gendev, skb->data, skb->len, + DMA_TO_DEVICE); + if (dma_mapping_error(vp->gendev, dma_addr)) goto out_dma_err; vp->tx_ring[entry].frag[0].addr = cpu_to_le32(dma_addr); @@ -2178,9 +2177,9 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev) } else { int i; - dma_addr = pci_map_single(VORTEX_PCI(vp), skb->data, - skb_headlen(skb), PCI_DMA_TODEVICE); - if (dma_mapping_error(&VORTEX_PCI(vp)->dev, dma_addr)) + dma_addr = dma_map_single(vp->gendev, skb->data, + skb_headlen(skb), DMA_TO_DEVICE); + if (dma_mapping_error(vp->gendev, dma_addr)) goto out_dma_err; vp->tx_ring[entry].frag[0].addr = cpu_to_le32(dma_addr); @@ -2189,21 +2188,21 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev) for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - dma_addr = skb_frag_dma_map(&VORTEX_PCI(vp)->dev, frag, + dma_addr = skb_frag_dma_map(vp->gendev, frag, 0, frag->size, DMA_TO_DEVICE); - if (dma_mapping_error(&VORTEX_PCI(vp)->dev, dma_addr)) { + if (dma_mapping_error(vp->gendev, dma_addr)) { for(i = i-1; i >= 0; i--) - dma_unmap_page(&VORTEX_PCI(vp)->dev, + dma_unmap_page(vp->gendev, le32_to_cpu(vp->tx_ring[entry].frag[i+1].addr), le32_to_cpu(vp->tx_ring[entry].frag[i+1].length), DMA_TO_DEVICE); - pci_unmap_single(VORTEX_PCI(vp), + dma_unmap_single(vp->gendev, le32_to_cpu(vp->tx_ring[entry].frag[0].addr), le32_to_cpu(vp->tx_ring[entry].frag[0].length), - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); goto out_dma_err; } @@ -2218,8 +2217,8 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev) } } #else - dma_addr = pci_map_single(VORTEX_PCI(vp), skb->data, skb->len, PCI_DMA_TODEVICE); - if (dma_mapping_error(&VORTEX_PCI(vp)->dev, dma_addr)) + dma_addr = dma_map_single(vp->gendev, skb->data, skb->len, DMA_TO_DEVICE); + if (dma_mapping_error(vp->gendev, dma_addr)) goto out_dma_err; vp->tx_ring[entry].addr = cpu_to_le32(dma_addr); vp->tx_ring[entry].length = cpu_to_le32(skb->len | LAST_FRAG); @@ -2254,7 +2253,7 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev) out: return NETDEV_TX_OK; out_dma_err: - dev_err(&VORTEX_PCI(vp)->dev, "Error mapping dma buffer\n"); + dev_err(vp->gendev, "Error mapping dma buffer\n"); goto out; } @@ -2322,7 +2321,7 @@ vortex_interrupt(int irq, void *dev_id) if (status & DMADone) { if (ioread16(ioaddr + Wn7_MasterStatus) & 0x1000) { iowrite16(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */ - pci_unmap_single(VORTEX_PCI(vp), vp->tx_skb_dma, (vp->tx_skb->len + 3) & ~3, PCI_DMA_TODEVICE); + dma_unmap_single(vp->gendev, vp->tx_skb_dma, (vp->tx_skb->len + 3) & ~3, DMA_TO_DEVICE); pkts_compl++; bytes_compl += vp->tx_skb->len; dev_kfree_skb_irq(vp->tx_skb); /* Release the transferred buffer */ @@ -2459,19 +2458,19 @@ boomerang_interrupt(int irq, void *dev_id) struct sk_buff *skb = vp->tx_skbuff[entry]; #if DO_ZEROCOPY int i; - pci_unmap_single(VORTEX_PCI(vp), + dma_unmap_single(vp->gendev, le32_to_cpu(vp->tx_ring[entry].frag[0].addr), le32_to_cpu(vp->tx_ring[entry].frag[0].length)&0xFFF, - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); for (i=1; i<=skb_shinfo(skb)->nr_frags; i++) - pci_unmap_page(VORTEX_PCI(vp), + dma_unmap_page(vp->gendev, le32_to_cpu(vp->tx_ring[entry].frag[i].addr), le32_to_cpu(vp->tx_ring[entry].frag[i].length)&0xFFF, - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); #else - pci_unmap_single(VORTEX_PCI(vp), - le32_to_cpu(vp->tx_ring[entry].addr), skb->len, PCI_DMA_TODEVICE); + dma_unmap_single(vp->gendev, + le32_to_cpu(vp->tx_ring[entry].addr), skb->len, DMA_TO_DEVICE); #endif pkts_compl++; bytes_compl += skb->len; @@ -2561,14 +2560,14 @@ static int vortex_rx(struct net_device *dev) /* 'skb_put()' points to the start of sk_buff data area. */ if (vp->bus_master && ! (ioread16(ioaddr + Wn7_MasterStatus) & 0x8000)) { - dma_addr_t dma = pci_map_single(VORTEX_PCI(vp), skb_put(skb, pkt_len), - pkt_len, PCI_DMA_FROMDEVICE); + dma_addr_t dma = dma_map_single(vp->gendev, skb_put(skb, pkt_len), + pkt_len, DMA_FROM_DEVICE); iowrite32(dma, ioaddr + Wn7_MasterAddr); iowrite16((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen); iowrite16(StartDMAUp, ioaddr + EL3_CMD); while (ioread16(ioaddr + Wn7_MasterStatus) & 0x8000) ; - pci_unmap_single(VORTEX_PCI(vp), dma, pkt_len, PCI_DMA_FROMDEVICE); + dma_unmap_single(vp->gendev, dma, pkt_len, DMA_FROM_DEVICE); } else { ioread32_rep(ioaddr + RX_FIFO, skb_put(skb, pkt_len), @@ -2635,11 +2634,11 @@ boomerang_rx(struct net_device *dev) if (pkt_len < rx_copybreak && (skb = netdev_alloc_skb(dev, pkt_len + 2)) != NULL) { skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - pci_dma_sync_single_for_cpu(VORTEX_PCI(vp), dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); + dma_sync_single_for_cpu(vp->gendev, dma, PKT_BUF_SZ, DMA_FROM_DEVICE); /* 'skb_put()' points to the start of sk_buff data area. */ skb_put_data(skb, vp->rx_skbuff[entry]->data, pkt_len); - pci_dma_sync_single_for_device(VORTEX_PCI(vp), dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); + dma_sync_single_for_device(vp->gendev, dma, PKT_BUF_SZ, DMA_FROM_DEVICE); vp->rx_copy++; } else { /* Pre-allocate the replacement skb. If it or its @@ -2651,9 +2650,9 @@ boomerang_rx(struct net_device *dev) dev->stats.rx_dropped++; goto clear_complete; } - newdma = pci_map_single(VORTEX_PCI(vp), newskb->data, - PKT_BUF_SZ, PCI_DMA_FROMDEVICE); - if (dma_mapping_error(&VORTEX_PCI(vp)->dev, newdma)) { + newdma = dma_map_single(vp->gendev, newskb->data, + PKT_BUF_SZ, DMA_FROM_DEVICE); + if (dma_mapping_error(vp->gendev, newdma)) { dev->stats.rx_dropped++; consume_skb(newskb); goto clear_complete; @@ -2664,7 +2663,7 @@ boomerang_rx(struct net_device *dev) vp->rx_skbuff[entry] = newskb; vp->rx_ring[entry].addr = cpu_to_le32(newdma); skb_put(skb, pkt_len); - pci_unmap_single(VORTEX_PCI(vp), dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); + dma_unmap_single(vp->gendev, dma, PKT_BUF_SZ, DMA_FROM_DEVICE); vp->rx_nocopy++; } skb->protocol = eth_type_trans(skb, dev); @@ -2761,8 +2760,8 @@ vortex_close(struct net_device *dev) if (vp->full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */ for (i = 0; i < RX_RING_SIZE; i++) if (vp->rx_skbuff[i]) { - pci_unmap_single( VORTEX_PCI(vp), le32_to_cpu(vp->rx_ring[i].addr), - PKT_BUF_SZ, PCI_DMA_FROMDEVICE); + dma_unmap_single(vp->gendev, le32_to_cpu(vp->rx_ring[i].addr), + PKT_BUF_SZ, DMA_FROM_DEVICE); dev_kfree_skb(vp->rx_skbuff[i]); vp->rx_skbuff[i] = NULL; } @@ -2775,12 +2774,12 @@ vortex_close(struct net_device *dev) int k; for (k=0; k<=skb_shinfo(skb)->nr_frags; k++) - pci_unmap_single(VORTEX_PCI(vp), + dma_unmap_single(vp->gendev, le32_to_cpu(vp->tx_ring[i].frag[k].addr), le32_to_cpu(vp->tx_ring[i].frag[k].length)&0xFFF, - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); #else - pci_unmap_single(VORTEX_PCI(vp), le32_to_cpu(vp->tx_ring[i].addr), skb->len, PCI_DMA_TODEVICE); + dma_unmap_single(vp->gendev, le32_to_cpu(vp->tx_ring[i].addr), skb->len, DMA_TO_DEVICE); #endif dev_kfree_skb(skb); vp->tx_skbuff[i] = NULL; @@ -3288,11 +3287,10 @@ static void vortex_remove_one(struct pci_dev *pdev) pci_iounmap(pdev, vp->ioaddr); - pci_free_consistent(pdev, - sizeof(struct boom_rx_desc) * RX_RING_SIZE - + sizeof(struct boom_tx_desc) * TX_RING_SIZE, - vp->rx_ring, - vp->rx_ring_dma); + dma_free_coherent(&pdev->dev, + sizeof(struct boom_rx_desc) * RX_RING_SIZE + + sizeof(struct boom_tx_desc) * TX_RING_SIZE, + vp->rx_ring, vp->rx_ring_dma); pci_release_regions(pdev); diff --git a/drivers/net/ethernet/8390/ne.c b/drivers/net/ethernet/8390/ne.c index ac99d089ac72..1c97e39b478e 100644 --- a/drivers/net/ethernet/8390/ne.c +++ b/drivers/net/ethernet/8390/ne.c @@ -164,7 +164,9 @@ bad_clone_list[] __initdata = { #define NESM_START_PG 0x40 /* First page of TX buffer */ #define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */ -#if defined(CONFIG_ATARI) /* 8-bit mode on Atari, normal on Q40 */ +#if defined(CONFIG_MACH_TX49XX) +# define DCR_VAL 0x48 /* 8-bit mode */ +#elif defined(CONFIG_ATARI) /* 8-bit mode on Atari, normal on Q40 */ # define DCR_VAL (MACH_IS_ATARI ? 0x48 : 0x49) #else # define DCR_VAL 0x49 diff --git a/drivers/net/ethernet/amd/pcnet32.c b/drivers/net/ethernet/amd/pcnet32.c index a561705f232c..be198cc0b10c 100644 --- a/drivers/net/ethernet/amd/pcnet32.c +++ b/drivers/net/ethernet/amd/pcnet32.c @@ -1552,22 +1552,26 @@ pcnet32_probe_pci(struct pci_dev *pdev, const struct pci_device_id *ent) if (!ioaddr) { if (pcnet32_debug & NETIF_MSG_PROBE) pr_err("card has no PCI IO resources, aborting\n"); - return -ENODEV; + err = -ENODEV; + goto err_disable_dev; } err = pci_set_dma_mask(pdev, PCNET32_DMA_MASK); if (err) { if (pcnet32_debug & NETIF_MSG_PROBE) pr_err("architecture does not support 32bit PCI busmaster DMA\n"); - return err; + goto err_disable_dev; } if (!request_region(ioaddr, PCNET32_TOTAL_SIZE, "pcnet32_probe_pci")) { if (pcnet32_debug & NETIF_MSG_PROBE) pr_err("io address range already allocated\n"); - return -EBUSY; + err = -EBUSY; + goto err_disable_dev; } err = pcnet32_probe1(ioaddr, 1, pdev); + +err_disable_dev: if (err < 0) pci_disable_device(pdev); diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h index b57acb8dc35b..dc25066c59a1 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h @@ -419,15 +419,15 @@ static const u32 t6_up_cim_reg_array[][IREG_NUM_ELEM + 1] = { {0x7b50, 0x7b54, 0x280, 0x20, 0}, /* up_cim_280_to_2fc */ {0x7b50, 0x7b54, 0x300, 0x20, 0}, /* up_cim_300_to_37c */ {0x7b50, 0x7b54, 0x380, 0x14, 0}, /* up_cim_380_to_3cc */ - {0x7b50, 0x7b54, 0x2900, 0x4, 0x4}, /* up_cim_2900_to_3d40 */ - {0x7b50, 0x7b54, 0x2904, 0x4, 0x4}, /* up_cim_2904_to_3d44 */ - {0x7b50, 0x7b54, 0x2908, 0x4, 0x4}, /* up_cim_2908_to_3d48 */ - {0x7b50, 0x7b54, 0x2910, 0x4, 0x4}, /* up_cim_2910_to_3d4c */ - {0x7b50, 0x7b54, 0x2914, 0x4, 0x4}, /* up_cim_2914_to_3d50 */ - {0x7b50, 0x7b54, 0x2920, 0x10, 0x10}, /* up_cim_2920_to_2a10 */ - {0x7b50, 0x7b54, 0x2924, 0x10, 0x10}, /* up_cim_2924_to_2a14 */ - {0x7b50, 0x7b54, 0x2928, 0x10, 0x10}, /* up_cim_2928_to_2a18 */ - {0x7b50, 0x7b54, 0x292c, 0x10, 0x10}, /* up_cim_292c_to_2a1c */ + {0x7b50, 0x7b54, 0x4900, 0x4, 0x4}, /* up_cim_4900_to_4c60 */ + {0x7b50, 0x7b54, 0x4904, 0x4, 0x4}, /* up_cim_4904_to_4c64 */ + {0x7b50, 0x7b54, 0x4908, 0x4, 0x4}, /* up_cim_4908_to_4c68 */ + {0x7b50, 0x7b54, 0x4910, 0x4, 0x4}, /* up_cim_4910_to_4c70 */ + {0x7b50, 0x7b54, 0x4914, 0x4, 0x4}, /* up_cim_4914_to_4c74 */ + {0x7b50, 0x7b54, 0x4920, 0x10, 0x10}, /* up_cim_4920_to_4a10 */ + {0x7b50, 0x7b54, 0x4924, 0x10, 0x10}, /* up_cim_4924_to_4a14 */ + {0x7b50, 0x7b54, 0x4928, 0x10, 0x10}, /* up_cim_4928_to_4a18 */ + {0x7b50, 0x7b54, 0x492c, 0x10, 0x10}, /* up_cim_492c_to_4a1c */ }; static const u32 t5_up_cim_reg_array[][IREG_NUM_ELEM + 1] = { @@ -444,16 +444,6 @@ static const u32 t5_up_cim_reg_array[][IREG_NUM_ELEM + 1] = { {0x7b50, 0x7b54, 0x280, 0x20, 0}, /* up_cim_280_to_2fc */ {0x7b50, 0x7b54, 0x300, 0x20, 0}, /* up_cim_300_to_37c */ {0x7b50, 0x7b54, 0x380, 0x14, 0}, /* up_cim_380_to_3cc */ - {0x7b50, 0x7b54, 0x2900, 0x4, 0x4}, /* up_cim_2900_to_3d40 */ - {0x7b50, 0x7b54, 0x2904, 0x4, 0x4}, /* up_cim_2904_to_3d44 */ - {0x7b50, 0x7b54, 0x2908, 0x4, 0x4}, /* up_cim_2908_to_3d48 */ - {0x7b50, 0x7b54, 0x2910, 0x4, 0x4}, /* up_cim_2910_to_3d4c */ - {0x7b50, 0x7b54, 0x2914, 0x4, 0x4}, /* up_cim_2914_to_3d50 */ - {0x7b50, 0x7b54, 0x2918, 0x4, 0x4}, /* up_cim_2918_to_3d54 */ - {0x7b50, 0x7b54, 0x291c, 0x4, 0x4}, /* up_cim_291c_to_3d58 */ - {0x7b50, 0x7b54, 0x2924, 0x10, 0x10}, /* up_cim_2924_to_2914 */ - {0x7b50, 0x7b54, 0x2928, 0x10, 0x10}, /* up_cim_2928_to_2a18 */ - {0x7b50, 0x7b54, 0x292c, 0x10, 0x10}, /* up_cim_292c_to_2a1c */ }; static const u32 t6_hma_ireg_array[][IREG_NUM_ELEM] = { diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c index db92f1858060..b76447baccaf 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c @@ -836,7 +836,7 @@ bool is_filter_exact_match(struct adapter *adap, { struct tp_params *tp = &adap->params.tp; u64 hash_filter_mask = tp->hash_filter_mask; - u32 mask; + u64 ntuple_mask = 0; if (!is_hashfilter(adap)) return false; @@ -865,73 +865,45 @@ bool is_filter_exact_match(struct adapter *adap, if (!fs->val.fport || fs->mask.fport != 0xffff) return false; - if (tp->fcoe_shift >= 0) { - mask = (hash_filter_mask >> tp->fcoe_shift) & FT_FCOE_W; - if (mask && !fs->mask.fcoe) - return false; - } + /* calculate tuple mask and compare with mask configured in hw */ + if (tp->fcoe_shift >= 0) + ntuple_mask |= (u64)fs->mask.fcoe << tp->fcoe_shift; - if (tp->port_shift >= 0) { - mask = (hash_filter_mask >> tp->port_shift) & FT_PORT_W; - if (mask && !fs->mask.iport) - return false; - } + if (tp->port_shift >= 0) + ntuple_mask |= (u64)fs->mask.iport << tp->port_shift; if (tp->vnic_shift >= 0) { - mask = (hash_filter_mask >> tp->vnic_shift) & FT_VNIC_ID_W; - - if ((adap->params.tp.ingress_config & VNIC_F)) { - if (mask && !fs->mask.pfvf_vld) - return false; - } else { - if (mask && !fs->mask.ovlan_vld) - return false; - } + if ((adap->params.tp.ingress_config & VNIC_F)) + ntuple_mask |= (u64)fs->mask.pfvf_vld << tp->vnic_shift; + else + ntuple_mask |= (u64)fs->mask.ovlan_vld << + tp->vnic_shift; } - if (tp->vlan_shift >= 0) { - mask = (hash_filter_mask >> tp->vlan_shift) & FT_VLAN_W; - if (mask && !fs->mask.ivlan) - return false; - } + if (tp->vlan_shift >= 0) + ntuple_mask |= (u64)fs->mask.ivlan << tp->vlan_shift; - if (tp->tos_shift >= 0) { - mask = (hash_filter_mask >> tp->tos_shift) & FT_TOS_W; - if (mask && !fs->mask.tos) - return false; - } + if (tp->tos_shift >= 0) + ntuple_mask |= (u64)fs->mask.tos << tp->tos_shift; - if (tp->protocol_shift >= 0) { - mask = (hash_filter_mask >> tp->protocol_shift) & FT_PROTOCOL_W; - if (mask && !fs->mask.proto) - return false; - } + if (tp->protocol_shift >= 0) + ntuple_mask |= (u64)fs->mask.proto << tp->protocol_shift; - if (tp->ethertype_shift >= 0) { - mask = (hash_filter_mask >> tp->ethertype_shift) & - FT_ETHERTYPE_W; - if (mask && !fs->mask.ethtype) - return false; - } + if (tp->ethertype_shift >= 0) + ntuple_mask |= (u64)fs->mask.ethtype << tp->ethertype_shift; - if (tp->macmatch_shift >= 0) { - mask = (hash_filter_mask >> tp->macmatch_shift) & FT_MACMATCH_W; - if (mask && !fs->mask.macidx) - return false; - } + if (tp->macmatch_shift >= 0) + ntuple_mask |= (u64)fs->mask.macidx << tp->macmatch_shift; + + if (tp->matchtype_shift >= 0) + ntuple_mask |= (u64)fs->mask.matchtype << tp->matchtype_shift; + + if (tp->frag_shift >= 0) + ntuple_mask |= (u64)fs->mask.frag << tp->frag_shift; + + if (ntuple_mask != hash_filter_mask) + return false; - if (tp->matchtype_shift >= 0) { - mask = (hash_filter_mask >> tp->matchtype_shift) & - FT_MPSHITTYPE_W; - if (mask && !fs->mask.matchtype) - return false; - } - if (tp->frag_shift >= 0) { - mask = (hash_filter_mask >> tp->frag_shift) & - FT_FRAGMENTATION_W; - if (mask && !fs->mask.frag) - return false; - } return true; } diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index 81684acf52af..8a8b12b720ef 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -2747,11 +2747,11 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_master(pdev); /* Query PCI controller on system for DMA addressing - * limitation for the device. Try 64-bit first, and + * limitation for the device. Try 47-bit first, and * fail to 32-bit. */ - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); + err = pci_set_dma_mask(pdev, DMA_BIT_MASK(47)); if (err) { err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (err) { @@ -2765,10 +2765,10 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_release_regions; } } else { - err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); + err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(47)); if (err) { dev_err(dev, "Unable to obtain %u-bit DMA " - "for consistent allocations, aborting\n", 64); + "for consistent allocations, aborting\n", 47); goto err_out_release_regions; } using_dac = 1; diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index c697e79e491e..8f755009ff38 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -3309,7 +3309,9 @@ void be_detect_error(struct be_adapter *adapter) if ((val & POST_STAGE_FAT_LOG_START) != POST_STAGE_FAT_LOG_START && (val & POST_STAGE_ARMFW_UE) - != POST_STAGE_ARMFW_UE) + != POST_STAGE_ARMFW_UE && + (val & POST_STAGE_RECOVERABLE_ERR) + != POST_STAGE_RECOVERABLE_ERR) return; } diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index d4604bc8eb5b..9d3eed46830d 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Fast Ethernet Controller (FEC) driver for Motorola MPC8xx. * Copyright (c) 1997 Dan Malek (dmalek@jlc.net) diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c index f81439796ac7..43d973215040 100644 --- a/drivers/net/ethernet/freescale/fec_ptp.c +++ b/drivers/net/ethernet/freescale/fec_ptp.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Fast Ethernet Controller (ENET) PTP driver for MX6x. * * Copyright (C) 2012 Freescale Semiconductor, Inc. - * - * 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. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 6e8d6a6f6aaf..5ec1185808e5 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -192,6 +192,7 @@ static int alloc_long_term_buff(struct ibmvnic_adapter *adapter, if (adapter->fw_done_rc) { dev_err(dev, "Couldn't map long term buffer,rc = %d\n", adapter->fw_done_rc); + dma_free_coherent(dev, ltb->size, ltb->buff, ltb->addr); return -1; } return 0; @@ -795,9 +796,11 @@ static int ibmvnic_login(struct net_device *netdev) struct ibmvnic_adapter *adapter = netdev_priv(netdev); unsigned long timeout = msecs_to_jiffies(30000); int retry_count = 0; + bool retry; int rc; do { + retry = false; if (retry_count > IBMVNIC_MAX_QUEUES) { netdev_warn(netdev, "Login attempts exceeded\n"); return -1; @@ -821,6 +824,9 @@ static int ibmvnic_login(struct net_device *netdev) retry_count++; release_sub_crqs(adapter, 1); + retry = true; + netdev_dbg(netdev, + "Received partial success, retrying...\n"); adapter->init_done_rc = 0; reinit_completion(&adapter->init_done); send_cap_queries(adapter); @@ -848,7 +854,7 @@ static int ibmvnic_login(struct net_device *netdev) netdev_warn(netdev, "Adapter login failed\n"); return -1; } - } while (adapter->init_done_rc == PARTIALSUCCESS); + } while (retry); /* handle pending MAC address changes after successful login */ if (adapter->mac_change_pending) { @@ -1821,9 +1827,8 @@ static int do_reset(struct ibmvnic_adapter *adapter, if (rc) return rc; } + ibmvnic_disable_irqs(adapter); } - - ibmvnic_disable_irqs(adapter); adapter->state = VNIC_CLOSED; if (reset_state == VNIC_CLOSED) @@ -2617,18 +2622,21 @@ static int enable_scrq_irq(struct ibmvnic_adapter *adapter, { struct device *dev = &adapter->vdev->dev; unsigned long rc; - u64 val; if (scrq->hw_irq > 0x100000000ULL) { dev_err(dev, "bad hw_irq = %lx\n", scrq->hw_irq); return 1; } - val = (0xff000000) | scrq->hw_irq; - rc = plpar_hcall_norets(H_EOI, val); - if (rc) - dev_err(dev, "H_EOI FAILED irq 0x%llx. rc=%ld\n", - val, rc); + if (adapter->resetting && + adapter->reset_reason == VNIC_RESET_MOBILITY) { + u64 val = (0xff000000) | scrq->hw_irq; + + rc = plpar_hcall_norets(H_EOI, val); + if (rc) + dev_err(dev, "H_EOI FAILED irq 0x%llx. rc=%ld\n", + val, rc); + } rc = plpar_hcall_norets(H_VIOCTL, adapter->vdev->unit_address, H_ENABLE_VIO_INTERRUPT, scrq->hw_irq, 0, 0); @@ -4586,14 +4594,6 @@ static int ibmvnic_init(struct ibmvnic_adapter *adapter) release_crq_queue(adapter); } - rc = init_stats_buffers(adapter); - if (rc) - return rc; - - rc = init_stats_token(adapter); - if (rc) - return rc; - return rc; } @@ -4662,13 +4662,21 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id) goto ibmvnic_init_fail; } while (rc == EAGAIN); + rc = init_stats_buffers(adapter); + if (rc) + goto ibmvnic_init_fail; + + rc = init_stats_token(adapter); + if (rc) + goto ibmvnic_stats_fail; + netdev->mtu = adapter->req_mtu - ETH_HLEN; netdev->min_mtu = adapter->min_mtu - ETH_HLEN; netdev->max_mtu = adapter->max_mtu - ETH_HLEN; rc = device_create_file(&dev->dev, &dev_attr_failover); if (rc) - goto ibmvnic_init_fail; + goto ibmvnic_dev_file_err; netif_carrier_off(netdev); rc = register_netdev(netdev); @@ -4687,6 +4695,12 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id) ibmvnic_register_fail: device_remove_file(&dev->dev, &dev_attr_failover); +ibmvnic_dev_file_err: + release_stats_token(adapter); + +ibmvnic_stats_fail: + release_stats_buffers(adapter); + ibmvnic_init_fail: release_sub_crqs(adapter, 1); release_crq_queue(adapter); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index afadba99f7b8..2ecd55856c50 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -9054,7 +9054,6 @@ static int parse_tc_actions(struct ixgbe_adapter *adapter, { const struct tc_action *a; LIST_HEAD(actions); - int err; if (!tcf_exts_has_actions(exts)) return -EINVAL; @@ -9075,11 +9074,11 @@ static int parse_tc_actions(struct ixgbe_adapter *adapter, if (!dev) return -EINVAL; - err = handle_redirect_action(adapter, dev->ifindex, queue, - action); - if (err == 0) - return err; + return handle_redirect_action(adapter, dev->ifindex, + queue, action); } + + return -EINVAL; } return -EINVAL; diff --git a/drivers/net/ethernet/mellanox/mlx4/icm.c b/drivers/net/ethernet/mellanox/mlx4/icm.c index a822f7a56bc5..685337d58276 100644 --- a/drivers/net/ethernet/mellanox/mlx4/icm.c +++ b/drivers/net/ethernet/mellanox/mlx4/icm.c @@ -43,12 +43,12 @@ #include "fw.h" /* - * We allocate in as big chunks as we can, up to a maximum of 256 KB - * per chunk. + * We allocate in page size (default 4KB on many archs) chunks to avoid high + * order memory allocations in fragmented/high usage memory situation. */ enum { - MLX4_ICM_ALLOC_SIZE = 1 << 18, - MLX4_TABLE_CHUNK_SIZE = 1 << 18 + MLX4_ICM_ALLOC_SIZE = PAGE_SIZE, + MLX4_TABLE_CHUNK_SIZE = PAGE_SIZE, }; static void mlx4_free_icm_pages(struct mlx4_dev *dev, struct mlx4_icm_chunk *chunk) @@ -398,9 +398,11 @@ int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table, u64 size; obj_per_chunk = MLX4_TABLE_CHUNK_SIZE / obj_size; + if (WARN_ON(!obj_per_chunk)) + return -EINVAL; num_icm = (nobj + obj_per_chunk - 1) / obj_per_chunk; - table->icm = kcalloc(num_icm, sizeof(*table->icm), GFP_KERNEL); + table->icm = kvzalloc(num_icm * sizeof(*table->icm), GFP_KERNEL); if (!table->icm) return -ENOMEM; table->virt = virt; @@ -446,7 +448,7 @@ err: mlx4_free_icm(dev, table->icm[i], use_coherent); } - kfree(table->icm); + kvfree(table->icm); return -ENOMEM; } @@ -462,5 +464,5 @@ void mlx4_cleanup_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table) mlx4_free_icm(dev, table->icm[i], table->coherent); } - kfree(table->icm); + kvfree(table->icm); } diff --git a/drivers/net/ethernet/mellanox/mlx4/intf.c b/drivers/net/ethernet/mellanox/mlx4/intf.c index 2edcce98ab2d..65482f004e50 100644 --- a/drivers/net/ethernet/mellanox/mlx4/intf.c +++ b/drivers/net/ethernet/mellanox/mlx4/intf.c @@ -172,7 +172,7 @@ int mlx4_do_bond(struct mlx4_dev *dev, bool enable) list_add_tail(&dev_ctx->list, &priv->ctx_list); spin_unlock_irqrestore(&priv->ctx_lock, flags); - mlx4_dbg(dev, "Inrerface for protocol %d restarted with when bonded mode is %s\n", + mlx4_dbg(dev, "Interface for protocol %d restarted with bonded mode %s\n", dev_ctx->intf->protocol, enable ? "enabled" : "disabled"); } diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 211578ffc70d..60172a38c4a4 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -2929,6 +2929,7 @@ static int mlx4_init_port_info(struct mlx4_dev *dev, int port) mlx4_err(dev, "Failed to create file for port %d\n", port); devlink_port_unregister(&info->devlink_port); info->port = -1; + return err; } sprintf(info->dev_mtu_name, "mlx4_port%d_mtu", port); @@ -2950,9 +2951,10 @@ static int mlx4_init_port_info(struct mlx4_dev *dev, int port) &info->port_attr); devlink_port_unregister(&info->devlink_port); info->port = -1; + return err; } - return err; + return 0; } static void mlx4_cleanup_port_info(struct mlx4_port_info *info) diff --git a/drivers/net/ethernet/mellanox/mlx4/qp.c b/drivers/net/ethernet/mellanox/mlx4/qp.c index 3aaf4bad6c5a..427e7a31862c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/qp.c +++ b/drivers/net/ethernet/mellanox/mlx4/qp.c @@ -393,11 +393,11 @@ struct mlx4_qp *mlx4_qp_lookup(struct mlx4_dev *dev, u32 qpn) struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table; struct mlx4_qp *qp; - spin_lock(&qp_table->lock); + spin_lock_irq(&qp_table->lock); qp = __mlx4_qp_lookup(dev, qpn); - spin_unlock(&qp_table->lock); + spin_unlock_irq(&qp_table->lock); return qp; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c index 176645762e49..1ff0b0e93804 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c @@ -615,6 +615,45 @@ static inline bool is_last_ethertype_ip(struct sk_buff *skb, int *network_depth) return (ethertype == htons(ETH_P_IP) || ethertype == htons(ETH_P_IPV6)); } +static __be32 mlx5e_get_fcs(struct sk_buff *skb) +{ + int last_frag_sz, bytes_in_prev, nr_frags; + u8 *fcs_p1, *fcs_p2; + skb_frag_t *last_frag; + __be32 fcs_bytes; + + if (!skb_is_nonlinear(skb)) + return *(__be32 *)(skb->data + skb->len - ETH_FCS_LEN); + + nr_frags = skb_shinfo(skb)->nr_frags; + last_frag = &skb_shinfo(skb)->frags[nr_frags - 1]; + last_frag_sz = skb_frag_size(last_frag); + + /* If all FCS data is in last frag */ + if (last_frag_sz >= ETH_FCS_LEN) + return *(__be32 *)(skb_frag_address(last_frag) + + last_frag_sz - ETH_FCS_LEN); + + fcs_p2 = (u8 *)skb_frag_address(last_frag); + bytes_in_prev = ETH_FCS_LEN - last_frag_sz; + + /* Find where the other part of the FCS is - Linear or another frag */ + if (nr_frags == 1) { + fcs_p1 = skb_tail_pointer(skb); + } else { + skb_frag_t *prev_frag = &skb_shinfo(skb)->frags[nr_frags - 2]; + + fcs_p1 = skb_frag_address(prev_frag) + + skb_frag_size(prev_frag); + } + fcs_p1 -= bytes_in_prev; + + memcpy(&fcs_bytes, fcs_p1, bytes_in_prev); + memcpy(((u8 *)&fcs_bytes) + bytes_in_prev, fcs_p2, last_frag_sz); + + return fcs_bytes; +} + static inline void mlx5e_handle_csum(struct net_device *netdev, struct mlx5_cqe64 *cqe, struct mlx5e_rq *rq, @@ -643,6 +682,9 @@ static inline void mlx5e_handle_csum(struct net_device *netdev, skb->csum = csum_partial(skb->data + ETH_HLEN, network_depth - ETH_HLEN, skb->csum); + if (unlikely(netdev->features & NETIF_F_RXFCS)) + skb->csum = csum_add(skb->csum, + (__force __wsum)mlx5e_get_fcs(skb)); rq->stats.csum_complete++; return; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c b/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c index 0f5da499a223..fad8c2e3804e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c @@ -237,19 +237,17 @@ static void *mlx5_fpga_ipsec_cmd_exec(struct mlx5_core_dev *mdev, context->buf.sg[0].data = &context->command; spin_lock_irqsave(&fdev->ipsec->pending_cmds_lock, flags); - list_add_tail(&context->list, &fdev->ipsec->pending_cmds); + res = mlx5_fpga_sbu_conn_sendmsg(fdev->ipsec->conn, &context->buf); + if (!res) + list_add_tail(&context->list, &fdev->ipsec->pending_cmds); spin_unlock_irqrestore(&fdev->ipsec->pending_cmds_lock, flags); - res = mlx5_fpga_sbu_conn_sendmsg(fdev->ipsec->conn, &context->buf); if (res) { - mlx5_fpga_warn(fdev, "Failure sending IPSec command: %d\n", - res); - spin_lock_irqsave(&fdev->ipsec->pending_cmds_lock, flags); - list_del(&context->list); - spin_unlock_irqrestore(&fdev->ipsec->pending_cmds_lock, flags); + mlx5_fpga_warn(fdev, "Failed to send IPSec command: %d\n", res); kfree(context); return ERR_PTR(res); } + /* Context will be freed by wait func after completion */ return context; } diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index ca38a30fbe91..adc6ab2cf429 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -4433,6 +4433,11 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev, NL_SET_ERR_MSG_MOD(extack, "Can not put a VLAN on an OVS port"); return -EINVAL; } + if (is_vlan_dev(upper_dev) && + vlan_dev_vlan_id(upper_dev) == 1) { + NL_SET_ERR_MSG_MOD(extack, "Creating a VLAN device with VID 1 is unsupported: VLAN 1 carries untagged traffic"); + return -EINVAL; + } break; case NETDEV_CHANGEUPPER: upper_dev = info->upper_dev; diff --git a/drivers/net/ethernet/natsemi/sonic.c b/drivers/net/ethernet/natsemi/sonic.c index 7ed08486ae23..c805dcbebd02 100644 --- a/drivers/net/ethernet/natsemi/sonic.c +++ b/drivers/net/ethernet/natsemi/sonic.c @@ -84,7 +84,7 @@ static int sonic_open(struct net_device *dev) for (i = 0; i < SONIC_NUM_RRS; i++) { dma_addr_t laddr = dma_map_single(lp->device, skb_put(lp->rx_skb[i], SONIC_RBSIZE), SONIC_RBSIZE, DMA_FROM_DEVICE); - if (!laddr) { + if (dma_mapping_error(lp->device, laddr)) { while(i > 0) { /* free any that were mapped successfully */ i--; dma_unmap_single(lp->device, lp->rx_laddr[i], SONIC_RBSIZE, DMA_FROM_DEVICE); diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.c b/drivers/net/ethernet/netronome/nfp/bpf/main.c index 1dc424685f4e..35fb31f682af 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/main.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/main.c @@ -335,7 +335,7 @@ static int nfp_bpf_parse_capabilities(struct nfp_app *app) return PTR_ERR(mem) == -ENOENT ? 0 : PTR_ERR(mem); start = mem; - while (mem - start + 8 < nfp_cpp_area_size(area)) { + while (mem - start + 8 <= nfp_cpp_area_size(area)) { u8 __iomem *value; u32 type, length; diff --git a/drivers/net/ethernet/qlogic/qed/qed_cxt.c b/drivers/net/ethernet/qlogic/qed/qed_cxt.c index 00f41c145d4d..820b226d6ff8 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_cxt.c +++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.c @@ -77,7 +77,7 @@ #define ILT_CFG_REG(cli, reg) PSWRQ2_REG_ ## cli ## _ ## reg ## _RT_OFFSET /* ILT entry structure */ -#define ILT_ENTRY_PHY_ADDR_MASK 0x000FFFFFFFFFFFULL +#define ILT_ENTRY_PHY_ADDR_MASK (~0ULL >> 12) #define ILT_ENTRY_PHY_ADDR_SHIFT 0 #define ILT_ENTRY_VALID_MASK 0x1ULL #define ILT_ENTRY_VALID_SHIFT 52 diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c b/drivers/net/ethernet/qlogic/qed/qed_ll2.c index 38502815d681..468c59d2e491 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c @@ -292,6 +292,7 @@ static void qed_ll2_txq_flush(struct qed_hwfn *p_hwfn, u8 connection_handle) struct qed_ll2_tx_packet *p_pkt = NULL; struct qed_ll2_info *p_ll2_conn; struct qed_ll2_tx_queue *p_tx; + unsigned long flags = 0; dma_addr_t tx_frag; p_ll2_conn = qed_ll2_handle_sanity_inactive(p_hwfn, connection_handle); @@ -300,6 +301,7 @@ static void qed_ll2_txq_flush(struct qed_hwfn *p_hwfn, u8 connection_handle) p_tx = &p_ll2_conn->tx_queue; + spin_lock_irqsave(&p_tx->lock, flags); while (!list_empty(&p_tx->active_descq)) { p_pkt = list_first_entry(&p_tx->active_descq, struct qed_ll2_tx_packet, list_entry); @@ -309,6 +311,7 @@ static void qed_ll2_txq_flush(struct qed_hwfn *p_hwfn, u8 connection_handle) list_del(&p_pkt->list_entry); b_last_packet = list_empty(&p_tx->active_descq); list_add_tail(&p_pkt->list_entry, &p_tx->free_descq); + spin_unlock_irqrestore(&p_tx->lock, flags); if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_OOO) { struct qed_ooo_buffer *p_buffer; @@ -328,7 +331,9 @@ static void qed_ll2_txq_flush(struct qed_hwfn *p_hwfn, u8 connection_handle) b_last_frag, b_last_packet); } + spin_lock_irqsave(&p_tx->lock, flags); } + spin_unlock_irqrestore(&p_tx->lock, flags); } static int qed_ll2_txq_completion(struct qed_hwfn *p_hwfn, void *p_cookie) @@ -556,6 +561,7 @@ static void qed_ll2_rxq_flush(struct qed_hwfn *p_hwfn, u8 connection_handle) struct qed_ll2_info *p_ll2_conn = NULL; struct qed_ll2_rx_packet *p_pkt = NULL; struct qed_ll2_rx_queue *p_rx; + unsigned long flags = 0; p_ll2_conn = qed_ll2_handle_sanity_inactive(p_hwfn, connection_handle); if (!p_ll2_conn) @@ -563,13 +569,14 @@ static void qed_ll2_rxq_flush(struct qed_hwfn *p_hwfn, u8 connection_handle) p_rx = &p_ll2_conn->rx_queue; + spin_lock_irqsave(&p_rx->lock, flags); while (!list_empty(&p_rx->active_descq)) { p_pkt = list_first_entry(&p_rx->active_descq, struct qed_ll2_rx_packet, list_entry); if (!p_pkt) break; - list_move_tail(&p_pkt->list_entry, &p_rx->free_descq); + spin_unlock_irqrestore(&p_rx->lock, flags); if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_OOO) { struct qed_ooo_buffer *p_buffer; @@ -588,7 +595,30 @@ static void qed_ll2_rxq_flush(struct qed_hwfn *p_hwfn, u8 connection_handle) cookie, rx_buf_addr, b_last); } + spin_lock_irqsave(&p_rx->lock, flags); } + spin_unlock_irqrestore(&p_rx->lock, flags); +} + +static bool +qed_ll2_lb_rxq_handler_slowpath(struct qed_hwfn *p_hwfn, + struct core_rx_slow_path_cqe *p_cqe) +{ + struct ooo_opaque *iscsi_ooo; + u32 cid; + + if (p_cqe->ramrod_cmd_id != CORE_RAMROD_RX_QUEUE_FLUSH) + return false; + + iscsi_ooo = (struct ooo_opaque *)&p_cqe->opaque_data; + if (iscsi_ooo->ooo_opcode != TCP_EVENT_DELETE_ISLES) + return false; + + /* Need to make a flush */ + cid = le32_to_cpu(iscsi_ooo->cid); + qed_ooo_release_connection_isles(p_hwfn, p_hwfn->p_ooo_info, cid); + + return true; } static int qed_ll2_lb_rxq_handler(struct qed_hwfn *p_hwfn, @@ -617,6 +647,11 @@ static int qed_ll2_lb_rxq_handler(struct qed_hwfn *p_hwfn, cq_old_idx = qed_chain_get_cons_idx(&p_rx->rcq_chain); cqe_type = cqe->rx_cqe_sp.type; + if (cqe_type == CORE_RX_CQE_TYPE_SLOW_PATH) + if (qed_ll2_lb_rxq_handler_slowpath(p_hwfn, + &cqe->rx_cqe_sp)) + continue; + if (cqe_type != CORE_RX_CQE_TYPE_REGULAR) { DP_NOTICE(p_hwfn, "Got a non-regular LB LL2 completion [type 0x%02x]\n", @@ -794,6 +829,9 @@ static int qed_ll2_lb_rxq_completion(struct qed_hwfn *p_hwfn, void *p_cookie) struct qed_ll2_info *p_ll2_conn = (struct qed_ll2_info *)p_cookie; int rc; + if (!QED_LL2_RX_REGISTERED(p_ll2_conn)) + return 0; + rc = qed_ll2_lb_rxq_handler(p_hwfn, p_ll2_conn); if (rc) return rc; @@ -814,6 +852,9 @@ static int qed_ll2_lb_txq_completion(struct qed_hwfn *p_hwfn, void *p_cookie) u16 new_idx = 0, num_bds = 0; int rc; + if (!QED_LL2_TX_REGISTERED(p_ll2_conn)) + return 0; + new_idx = le16_to_cpu(*p_tx->p_fw_cons); num_bds = ((s16)new_idx - (s16)p_tx->bds_idx); @@ -1867,17 +1908,25 @@ int qed_ll2_terminate_connection(void *cxt, u8 connection_handle) /* Stop Tx & Rx of connection, if needed */ if (QED_LL2_TX_REGISTERED(p_ll2_conn)) { + p_ll2_conn->tx_queue.b_cb_registred = false; + smp_wmb(); /* Make sure this is seen by ll2_lb_rxq_completion */ rc = qed_sp_ll2_tx_queue_stop(p_hwfn, p_ll2_conn); if (rc) goto out; + qed_ll2_txq_flush(p_hwfn, connection_handle); + qed_int_unregister_cb(p_hwfn, p_ll2_conn->tx_queue.tx_sb_index); } if (QED_LL2_RX_REGISTERED(p_ll2_conn)) { + p_ll2_conn->rx_queue.b_cb_registred = false; + smp_wmb(); /* Make sure this is seen by ll2_lb_rxq_completion */ rc = qed_sp_ll2_rx_queue_stop(p_hwfn, p_ll2_conn); if (rc) goto out; + qed_ll2_rxq_flush(p_hwfn, connection_handle); + qed_int_unregister_cb(p_hwfn, p_ll2_conn->rx_queue.rx_sb_index); } if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_OOO) @@ -1925,16 +1974,6 @@ void qed_ll2_release_connection(void *cxt, u8 connection_handle) if (!p_ll2_conn) return; - if (QED_LL2_RX_REGISTERED(p_ll2_conn)) { - p_ll2_conn->rx_queue.b_cb_registred = false; - qed_int_unregister_cb(p_hwfn, p_ll2_conn->rx_queue.rx_sb_index); - } - - if (QED_LL2_TX_REGISTERED(p_ll2_conn)) { - p_ll2_conn->tx_queue.b_cb_registred = false; - qed_int_unregister_cb(p_hwfn, p_ll2_conn->tx_queue.tx_sb_index); - } - kfree(p_ll2_conn->tx_queue.descq_mem); qed_chain_free(p_hwfn->cdev, &p_ll2_conn->tx_queue.txq_chain); diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c index a01e7d6e5442..f6655e251bbd 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_main.c +++ b/drivers/net/ethernet/qlogic/qede/qede_main.c @@ -1066,13 +1066,12 @@ static void __qede_remove(struct pci_dev *pdev, enum qede_remove_mode mode) DP_INFO(edev, "Starting qede_remove\n"); + qede_rdma_dev_remove(edev); unregister_netdev(ndev); cancel_delayed_work_sync(&edev->sp_task); qede_ptp_disable(edev); - qede_rdma_dev_remove(edev); - edev->ops->common->set_power_state(cdev, PCI_D0); pci_set_drvdata(pdev, NULL); diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h index a5b792ce2ae7..1bf930d4a1e5 100644 --- a/drivers/net/ethernet/renesas/sh_eth.h +++ b/drivers/net/ethernet/renesas/sh_eth.h @@ -163,7 +163,7 @@ enum { }; /* Driver's parameters */ -#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE) +#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_RENESAS) #define SH_ETH_RX_ALIGN 32 #else #define SH_ETH_RX_ALIGN 2 diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index a4ebd8715494..661828e8fdcf 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -1289,9 +1289,8 @@ static int efx_init_io(struct efx_nic *efx) pci_set_master(pci_dev); - /* Set the PCI DMA mask. Try all possibilities from our - * genuine mask down to 32 bits, because some architectures - * (e.g. x86_64 with iommu_sac_force set) will allow 40 bit + /* Set the PCI DMA mask. Try all possibilities from our genuine mask + * down to 32 bits, because some architectures will allow 40 bit * masks event though they reject 46 bit masks. */ while (dma_mask > 0x7fffffffUL) { diff --git a/drivers/net/ethernet/sfc/falcon/efx.c b/drivers/net/ethernet/sfc/falcon/efx.c index 3d6c91e96589..dd5530a4f8c8 100644 --- a/drivers/net/ethernet/sfc/falcon/efx.c +++ b/drivers/net/ethernet/sfc/falcon/efx.c @@ -1242,9 +1242,8 @@ static int ef4_init_io(struct ef4_nic *efx) pci_set_master(pci_dev); - /* Set the PCI DMA mask. Try all possibilities from our - * genuine mask down to 32 bits, because some architectures - * (e.g. x86_64 with iommu_sac_force set) will allow 40 bit + /* Set the PCI DMA mask. Try all possibilities from our genuine mask + * down to 32 bits, because some architectures will allow 40 bit * masks event though they reject 46 bit masks. */ while (dma_mask > 0x7fffffffUL) { diff --git a/drivers/net/ethernet/socionext/netsec.c b/drivers/net/ethernet/socionext/netsec.c index f4c0b02ddad8..59fbf74dcada 100644 --- a/drivers/net/ethernet/socionext/netsec.c +++ b/drivers/net/ethernet/socionext/netsec.c @@ -1674,8 +1674,8 @@ static int netsec_probe(struct platform_device *pdev) if (ret) goto unreg_napi; - if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64))) - dev_warn(&pdev->dev, "Failed to enable 64-bit DMA\n"); + if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40))) + dev_warn(&pdev->dev, "Failed to set DMA mask\n"); ret = register_netdev(ndev); if (ret) { diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c index abceea802ea1..38828ab77eb9 100644 --- a/drivers/net/ethernet/ti/davinci_emac.c +++ b/drivers/net/ethernet/ti/davinci_emac.c @@ -1873,7 +1873,7 @@ static int davinci_emac_probe(struct platform_device *pdev) if (IS_ERR(priv->txchan)) { dev_err(&pdev->dev, "error initializing tx dma channel\n"); rc = PTR_ERR(priv->txchan); - goto no_cpdma_chan; + goto err_free_dma; } priv->rxchan = cpdma_chan_create(priv->dma, EMAC_DEF_RX_CH, @@ -1881,14 +1881,14 @@ static int davinci_emac_probe(struct platform_device *pdev) if (IS_ERR(priv->rxchan)) { dev_err(&pdev->dev, "error initializing rx dma channel\n"); rc = PTR_ERR(priv->rxchan); - goto no_cpdma_chan; + goto err_free_txchan; } res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!res) { dev_err(&pdev->dev, "error getting irq res\n"); rc = -ENOENT; - goto no_cpdma_chan; + goto err_free_rxchan; } ndev->irq = res->start; @@ -1914,7 +1914,7 @@ static int davinci_emac_probe(struct platform_device *pdev) pm_runtime_put_noidle(&pdev->dev); dev_err(&pdev->dev, "%s: failed to get_sync(%d)\n", __func__, rc); - goto no_cpdma_chan; + goto err_napi_del; } /* register the network device */ @@ -1924,7 +1924,7 @@ static int davinci_emac_probe(struct platform_device *pdev) dev_err(&pdev->dev, "error in register_netdev\n"); rc = -ENODEV; pm_runtime_put(&pdev->dev); - goto no_cpdma_chan; + goto err_napi_del; } @@ -1937,11 +1937,13 @@ static int davinci_emac_probe(struct platform_device *pdev) return 0; -no_cpdma_chan: - if (priv->txchan) - cpdma_chan_destroy(priv->txchan); - if (priv->rxchan) - cpdma_chan_destroy(priv->rxchan); +err_napi_del: + netif_napi_del(&priv->napi); +err_free_rxchan: + cpdma_chan_destroy(priv->rxchan); +err_free_txchan: + cpdma_chan_destroy(priv->txchan); +err_free_dma: cpdma_ctlr_destroy(priv->dma); no_pdata: if (of_phy_is_fixed_link(np)) diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index dfabbae72efd..f347fd9c5b28 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -449,20 +449,6 @@ static const struct seq_operations bpq_seqops = { .show = bpq_seq_show, }; -static int bpq_info_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &bpq_seqops); -} - -static const struct file_operations bpq_info_fops = { - .owner = THIS_MODULE, - .open = bpq_info_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - - /* ------------------------------------------------------------------------ */ static const struct net_device_ops bpq_netdev_ops = { @@ -590,7 +576,7 @@ static int bpq_device_event(struct notifier_block *this, static int __init bpq_init_driver(void) { #ifdef CONFIG_PROC_FS - if (!proc_create("bpqether", 0444, init_net.proc_net, &bpq_info_fops)) { + if (!proc_create_seq("bpqether", 0444, init_net.proc_net, &bpq_seqops)) { printk(KERN_ERR "bpq: cannot create /proc/net/bpqether entry.\n"); return -ENOENT; diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index 3de272959090..6c03932d8a6b 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -2084,21 +2084,6 @@ static const struct seq_operations scc_net_seq_ops = { .stop = scc_net_seq_stop, .show = scc_net_seq_show, }; - - -static int scc_net_seq_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &scc_net_seq_ops); -} - -static const struct file_operations scc_net_seq_fops = { - .owner = THIS_MODULE, - .open = scc_net_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_private, -}; - #endif /* CONFIG_PROC_FS */ @@ -2122,7 +2107,7 @@ static int __init scc_init_driver (void) } rtnl_unlock(); - proc_create("z8530drv", 0, init_net.proc_net, &scc_net_seq_fops); + proc_create_seq("z8530drv", 0, init_net.proc_net, &scc_net_seq_ops); return 0; } diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c index 83034eb7ed4f..16ec7af6ab7b 100644 --- a/drivers/net/hamradio/yam.c +++ b/drivers/net/hamradio/yam.c @@ -841,20 +841,6 @@ static const struct seq_operations yam_seqops = { .stop = yam_seq_stop, .show = yam_seq_show, }; - -static int yam_info_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &yam_seqops); -} - -static const struct file_operations yam_info_fops = { - .owner = THIS_MODULE, - .open = yam_info_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - #endif @@ -1168,7 +1154,7 @@ static int __init yam_init_driver(void) yam_timer.expires = jiffies + HZ / 100; add_timer(&yam_timer); - proc_create("yam", 0444, init_net.proc_net, &yam_info_fops); + proc_create_seq("yam", 0444, init_net.proc_net, &yam_seqops); return 0; error: while (--i >= 0) { diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c index 450eec264a5e..4377c26f714d 100644 --- a/drivers/net/ipvlan/ipvlan_main.c +++ b/drivers/net/ipvlan/ipvlan_main.c @@ -792,8 +792,10 @@ static int ipvlan_device_event(struct notifier_block *unused, break; case NETDEV_CHANGEADDR: - list_for_each_entry(ipvlan, &port->ipvlans, pnode) + list_for_each_entry(ipvlan, &port->ipvlans, pnode) { ether_addr_copy(ipvlan->dev->dev_addr, dev->dev_addr); + call_netdevice_notifiers(NETDEV_CHANGEADDR, ipvlan->dev); + } break; case NETDEV_PRE_TYPE_CHANGE: diff --git a/drivers/net/phy/bcm-cygnus.c b/drivers/net/phy/bcm-cygnus.c index 6838129839ca..e757b09f1889 100644 --- a/drivers/net/phy/bcm-cygnus.c +++ b/drivers/net/phy/bcm-cygnus.c @@ -61,17 +61,17 @@ static int bcm_cygnus_afe_config(struct phy_device *phydev) return rc; /* make rcal=100, since rdb default is 000 */ - rc = bcm_phy_write_exp(phydev, MII_BRCM_CORE_EXPB1, 0x10); + rc = bcm_phy_write_exp_sel(phydev, MII_BRCM_CORE_EXPB1, 0x10); if (rc < 0) return rc; /* CORE_EXPB0, Reset R_CAL/RC_CAL Engine */ - rc = bcm_phy_write_exp(phydev, MII_BRCM_CORE_EXPB0, 0x10); + rc = bcm_phy_write_exp_sel(phydev, MII_BRCM_CORE_EXPB0, 0x10); if (rc < 0) return rc; /* CORE_EXPB0, Disable Reset R_CAL/RC_CAL Engine */ - rc = bcm_phy_write_exp(phydev, MII_BRCM_CORE_EXPB0, 0x00); + rc = bcm_phy_write_exp_sel(phydev, MII_BRCM_CORE_EXPB0, 0x00); return 0; } diff --git a/drivers/net/phy/bcm-phy-lib.c b/drivers/net/phy/bcm-phy-lib.c index 5ad130c3da43..d5e0833d69b9 100644 --- a/drivers/net/phy/bcm-phy-lib.c +++ b/drivers/net/phy/bcm-phy-lib.c @@ -56,7 +56,7 @@ int bcm54xx_auxctl_read(struct phy_device *phydev, u16 regnum) /* The register must be written to both the Shadow Register Select and * the Shadow Read Register Selector */ - phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum | + phy_write(phydev, MII_BCM54XX_AUX_CTL, MII_BCM54XX_AUXCTL_SHDWSEL_MASK | regnum << MII_BCM54XX_AUXCTL_SHDWSEL_READ_SHIFT); return phy_read(phydev, MII_BCM54XX_AUX_CTL); } diff --git a/drivers/net/phy/bcm-phy-lib.h b/drivers/net/phy/bcm-phy-lib.h index 7c73808cbbde..81cceaa412fe 100644 --- a/drivers/net/phy/bcm-phy-lib.h +++ b/drivers/net/phy/bcm-phy-lib.h @@ -14,11 +14,18 @@ #ifndef _LINUX_BCM_PHY_LIB_H #define _LINUX_BCM_PHY_LIB_H +#include <linux/brcmphy.h> #include <linux/phy.h> int bcm_phy_write_exp(struct phy_device *phydev, u16 reg, u16 val); int bcm_phy_read_exp(struct phy_device *phydev, u16 reg); +static inline int bcm_phy_write_exp_sel(struct phy_device *phydev, + u16 reg, u16 val) +{ + return bcm_phy_write_exp(phydev, reg | MII_BCM54XX_EXP_SEL_ER, val); +} + int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val); int bcm54xx_auxctl_read(struct phy_device *phydev, u16 regnum); diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c index 29b1c88b55cc..01d2ff2f6241 100644 --- a/drivers/net/phy/bcm7xxx.c +++ b/drivers/net/phy/bcm7xxx.c @@ -65,10 +65,10 @@ struct bcm7xxx_phy_priv { static void r_rc_cal_reset(struct phy_device *phydev) { /* Reset R_CAL/RC_CAL Engine */ - bcm_phy_write_exp(phydev, 0x00b0, 0x0010); + bcm_phy_write_exp_sel(phydev, 0x00b0, 0x0010); /* Disable Reset R_AL/RC_CAL Engine */ - bcm_phy_write_exp(phydev, 0x00b0, 0x0000); + bcm_phy_write_exp_sel(phydev, 0x00b0, 0x0000); } static int bcm7xxx_28nm_b0_afe_config_init(struct phy_device *phydev) diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index f41b224a9cdb..ab195f0916d6 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -573,9 +573,40 @@ static int ksz9031_config_init(struct phy_device *phydev) ksz9031_of_load_skew_values(phydev, of_node, MII_KSZ9031RN_TX_DATA_PAD_SKEW, 4, tx_data_skews, 4); + + /* Silicon Errata Sheet (DS80000691D or DS80000692D): + * When the device links in the 1000BASE-T slave mode only, + * the optional 125MHz reference output clock (CLK125_NDO) + * has wide duty cycle variation. + * + * The optional CLK125_NDO clock does not meet the RGMII + * 45/55 percent (min/max) duty cycle requirement and therefore + * cannot be used directly by the MAC side for clocking + * applications that have setup/hold time requirements on + * rising and falling clock edges. + * + * Workaround: + * Force the phy to be the master to receive a stable clock + * which meets the duty cycle requirement. + */ + if (of_property_read_bool(of_node, "micrel,force-master")) { + result = phy_read(phydev, MII_CTRL1000); + if (result < 0) + goto err_force_master; + + /* enable master mode, config & prefer master */ + result |= CTL1000_ENABLE_MASTER | CTL1000_AS_MASTER; + result = phy_write(phydev, MII_CTRL1000, result); + if (result < 0) + goto err_force_master; + } } return ksz9031_center_flp_timing(phydev); + +err_force_master: + phydev_err(phydev, "failed to force the phy to master mode\n"); + return result; } #define KSZ8873MLL_GLOBAL_CONTROL_4 0x06 diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index dc7c7ec43202..02ad03a2fab7 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@ -605,30 +605,13 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) if (cmd == PPPIOCDETACH) { /* - * We have to be careful here... if the file descriptor - * has been dup'd, we could have another process in the - * middle of a poll using the same file *, so we had - * better not free the interface data structures - - * instead we fail the ioctl. Even in this case, we - * shut down the interface if we are the owner of it. - * Actually, we should get rid of PPPIOCDETACH, userland - * (i.e. pppd) could achieve the same effect by closing - * this fd and reopening /dev/ppp. + * PPPIOCDETACH is no longer supported as it was heavily broken, + * and is only known to have been used by pppd older than + * ppp-2.4.2 (released November 2003). */ + pr_warn_once("%s (%d) used obsolete PPPIOCDETACH ioctl\n", + current->comm, current->pid); err = -EINVAL; - if (pf->kind == INTERFACE) { - ppp = PF_TO_PPP(pf); - rtnl_lock(); - if (file == ppp->owner) - unregister_netdevice(ppp->dev); - rtnl_unlock(); - } - if (atomic_long_read(&file->f_count) < 2) { - ppp_release(NULL, file); - err = 0; - } else - pr_warn("PPPIOCDETACH file->f_count=%ld\n", - atomic_long_read(&file->f_count)); goto out; } diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c index 7df07337d69c..de51e8f70f44 100644 --- a/drivers/net/ppp/pppoe.c +++ b/drivers/net/ppp/pppoe.c @@ -1096,21 +1096,6 @@ static const struct seq_operations pppoe_seq_ops = { .stop = pppoe_seq_stop, .show = pppoe_seq_show, }; - -static int pppoe_seq_open(struct inode *inode, struct file *file) -{ - return seq_open_net(inode, file, &pppoe_seq_ops, - sizeof(struct seq_net_private)); -} - -static const struct file_operations pppoe_seq_fops = { - .owner = THIS_MODULE, - .open = pppoe_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_net, -}; - #endif /* CONFIG_PROC_FS */ static const struct proto_ops pppoe_ops = { @@ -1122,7 +1107,7 @@ static const struct proto_ops pppoe_ops = { .socketpair = sock_no_socketpair, .accept = sock_no_accept, .getname = pppoe_getname, - .poll = datagram_poll, + .poll_mask = datagram_poll_mask, .listen = sock_no_listen, .shutdown = sock_no_shutdown, .setsockopt = sock_no_setsockopt, @@ -1146,7 +1131,8 @@ static __net_init int pppoe_init_net(struct net *net) rwlock_init(&pn->hash_lock); - pde = proc_create("pppoe", 0444, net->proc_net, &pppoe_seq_fops); + pde = proc_create_net("pppoe", 0444, net->proc_net, + &pppoe_seq_ops, sizeof(struct seq_net_private)); #ifdef CONFIG_PROC_FS if (!pde) return -ENOMEM; diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c index c4267ecefd85..157b67c1bf8e 100644 --- a/drivers/net/ppp/pptp.c +++ b/drivers/net/ppp/pptp.c @@ -624,7 +624,6 @@ static const struct proto_ops pptp_ops = { .socketpair = sock_no_socketpair, .accept = sock_no_accept, .getname = pptp_getname, - .poll = sock_no_poll, .listen = sock_no_listen, .shutdown = sock_no_shutdown, .setsockopt = sock_no_setsockopt, diff --git a/drivers/net/tun.c b/drivers/net/tun.c index ef33950a45d9..23e9eb66197f 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -681,15 +681,6 @@ static void tun_queue_purge(struct tun_file *tfile) skb_queue_purge(&tfile->sk.sk_error_queue); } -static void tun_cleanup_tx_ring(struct tun_file *tfile) -{ - if (tfile->tx_ring.queue) { - ptr_ring_cleanup(&tfile->tx_ring, tun_ptr_free); - xdp_rxq_info_unreg(&tfile->xdp_rxq); - memset(&tfile->tx_ring, 0, sizeof(tfile->tx_ring)); - } -} - static void __tun_detach(struct tun_file *tfile, bool clean) { struct tun_file *ntfile; @@ -736,7 +727,9 @@ static void __tun_detach(struct tun_file *tfile, bool clean) tun->dev->reg_state == NETREG_REGISTERED) unregister_netdevice(tun->dev); } - tun_cleanup_tx_ring(tfile); + if (tun) + xdp_rxq_info_unreg(&tfile->xdp_rxq); + ptr_ring_cleanup(&tfile->tx_ring, tun_ptr_free); sock_put(&tfile->sk); } } @@ -783,14 +776,14 @@ static void tun_detach_all(struct net_device *dev) tun_napi_del(tun, tfile); /* Drop read queue */ tun_queue_purge(tfile); + xdp_rxq_info_unreg(&tfile->xdp_rxq); sock_put(&tfile->sk); - tun_cleanup_tx_ring(tfile); } list_for_each_entry_safe(tfile, tmp, &tun->disabled, next) { tun_enable_queue(tfile); tun_queue_purge(tfile); + xdp_rxq_info_unreg(&tfile->xdp_rxq); sock_put(&tfile->sk); - tun_cleanup_tx_ring(tfile); } BUG_ON(tun->numdisabled != 0); @@ -834,7 +827,8 @@ static int tun_attach(struct tun_struct *tun, struct file *file, } if (!tfile->detached && - ptr_ring_init(&tfile->tx_ring, dev->tx_queue_len, GFP_KERNEL)) { + ptr_ring_resize(&tfile->tx_ring, dev->tx_queue_len, + GFP_KERNEL, tun_ptr_free)) { err = -ENOMEM; goto out; } @@ -1429,6 +1423,13 @@ static void tun_net_init(struct net_device *dev) dev->max_mtu = MAX_MTU - dev->hard_header_len; } +static bool tun_sock_writeable(struct tun_struct *tun, struct tun_file *tfile) +{ + struct sock *sk = tfile->socket.sk; + + return (tun->dev->flags & IFF_UP) && sock_writeable(sk); +} + /* Character device part */ /* Poll */ @@ -1451,10 +1452,14 @@ static __poll_t tun_chr_poll(struct file *file, poll_table *wait) if (!ptr_ring_empty(&tfile->tx_ring)) mask |= EPOLLIN | EPOLLRDNORM; - if (tun->dev->flags & IFF_UP && - (sock_writeable(sk) || - (!test_and_set_bit(SOCKWQ_ASYNC_NOSPACE, &sk->sk_socket->flags) && - sock_writeable(sk)))) + /* Make sure SOCKWQ_ASYNC_NOSPACE is set if not writable to + * guarantee EPOLLOUT to be raised by either here or + * tun_sock_write_space(). Then process could get notification + * after it writes to a down device and meets -EIO. + */ + if (tun_sock_writeable(tun, tfile) || + (!test_and_set_bit(SOCKWQ_ASYNC_NOSPACE, &sk->sk_socket->flags) && + tun_sock_writeable(tun, tfile))) mask |= EPOLLOUT | EPOLLWRNORM; if (tun->dev->reg_state != NETREG_REGISTERED) @@ -1645,7 +1650,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, else *skb_xdp = 0; - preempt_disable(); + local_bh_disable(); rcu_read_lock(); xdp_prog = rcu_dereference(tun->xdp_prog); if (xdp_prog && !*skb_xdp) { @@ -1670,7 +1675,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, if (err) goto err_redirect; rcu_read_unlock(); - preempt_enable(); + local_bh_enable(); return NULL; case XDP_TX: get_page(alloc_frag->page); @@ -1679,7 +1684,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, goto err_redirect; tun_xdp_flush(tun->dev); rcu_read_unlock(); - preempt_enable(); + local_bh_enable(); return NULL; case XDP_PASS: delta = orig_data - xdp.data; @@ -1698,7 +1703,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, skb = build_skb(buf, buflen); if (!skb) { rcu_read_unlock(); - preempt_enable(); + local_bh_enable(); return ERR_PTR(-ENOMEM); } @@ -1708,7 +1713,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, alloc_frag->offset += buflen; rcu_read_unlock(); - preempt_enable(); + local_bh_enable(); return skb; @@ -1716,7 +1721,7 @@ err_redirect: put_page(alloc_frag->page); err_xdp: rcu_read_unlock(); - preempt_enable(); + local_bh_enable(); this_cpu_inc(tun->pcpu_stats->rx_dropped); return NULL; } @@ -1912,16 +1917,19 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, struct bpf_prog *xdp_prog; int ret; + local_bh_disable(); rcu_read_lock(); xdp_prog = rcu_dereference(tun->xdp_prog); if (xdp_prog) { ret = do_xdp_generic(xdp_prog, skb); if (ret != XDP_PASS) { rcu_read_unlock(); + local_bh_enable(); return total_len; } } rcu_read_unlock(); + local_bh_enable(); } rcu_read_lock(); @@ -3219,6 +3227,11 @@ static int tun_chr_open(struct inode *inode, struct file * file) &tun_proto, 0); if (!tfile) return -ENOMEM; + if (ptr_ring_init(&tfile->tx_ring, 0, GFP_KERNEL)) { + sk_free(&tfile->sk); + return -ENOMEM; + } + RCU_INIT_POINTER(tfile->tun, NULL); tfile->flags = 0; tfile->ifindex = 0; @@ -3239,8 +3252,6 @@ static int tun_chr_open(struct inode *inode, struct file * file) sock_set_flag(&tfile->sk, SOCK_ZEROCOPY); - memset(&tfile->tx_ring, 0, sizeof(tfile->tx_ring)); - return 0; } diff --git a/drivers/net/usb/cdc_mbim.c b/drivers/net/usb/cdc_mbim.c index 7220cd620717..0362acd5cdca 100644 --- a/drivers/net/usb/cdc_mbim.c +++ b/drivers/net/usb/cdc_mbim.c @@ -609,7 +609,7 @@ static const struct driver_info cdc_mbim_info_ndp_to_end = { */ static const struct driver_info cdc_mbim_info_avoid_altsetting_toggle = { .description = "CDC MBIM", - .flags = FLAG_NO_SETINT | FLAG_MULTI_PACKET | FLAG_WWAN, + .flags = FLAG_NO_SETINT | FLAG_MULTI_PACKET | FLAG_WWAN | FLAG_SEND_ZLP, .bind = cdc_mbim_bind, .unbind = cdc_mbim_unbind, .manage_power = cdc_mbim_manage_power, diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 42565dd33aa6..094680871687 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -1103,6 +1103,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x05c6, 0x920d, 5)}, {QMI_QUIRK_SET_DTR(0x05c6, 0x9625, 4)}, /* YUGA CLM920-NC5 */ {QMI_FIXED_INTF(0x0846, 0x68a2, 8)}, + {QMI_FIXED_INTF(0x0846, 0x68d3, 8)}, /* Netgear Aircard 779S */ {QMI_FIXED_INTF(0x12d1, 0x140c, 1)}, /* Huawei E173 */ {QMI_FIXED_INTF(0x12d1, 0x14ac, 1)}, /* Huawei E1820 */ {QMI_FIXED_INTF(0x1435, 0xd181, 3)}, /* Wistron NeWeb D18Q1 */ diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 770422e953f7..032e1ac10a30 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -707,6 +707,13 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, void *data; u32 act; + /* Transient failure which in theory could occur if + * in-flight packets from before XDP was enabled reach + * the receive path after XDP is loaded. + */ + if (unlikely(hdr->hdr.gso_type)) + goto err_xdp; + /* This happens when rx buffer size is underestimated * or headroom is not enough because of the buffer * was refilled before XDP is set. This should only @@ -727,14 +734,6 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, xdp_page = page; } - /* Transient failure which in theory could occur if - * in-flight packets from before XDP was enabled reach - * the receive path after XDP is loaded. In practice I - * was not able to create this condition. - */ - if (unlikely(hdr->hdr.gso_type)) - goto err_xdp; - /* Allow consuming headroom but reserve enough space to push * the descriptor on if we get an XDP_TX return code. */ @@ -775,7 +774,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, } *xdp_xmit = true; if (unlikely(xdp_page != page)) - goto err_xdp; + put_page(page); rcu_read_unlock(); goto xdp_xmit; case XDP_REDIRECT: @@ -787,7 +786,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, } *xdp_xmit = true; if (unlikely(xdp_page != page)) - goto err_xdp; + put_page(page); rcu_read_unlock(); goto xdp_xmit; default: @@ -875,7 +874,7 @@ err_xdp: rcu_read_unlock(); err_skb: put_page(page); - while (--num_buf) { + while (num_buf-- > 1) { buf = virtqueue_get_buf(rq->vq, &len); if (unlikely(!buf)) { pr_debug("%s: rx error: %d buffers missing\n", diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index 9ebe2a689966..27a9bb8c9611 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -369,6 +369,11 @@ vmxnet3_tq_tx_complete(struct vmxnet3_tx_queue *tq, gdesc = tq->comp_ring.base + tq->comp_ring.next2proc; while (VMXNET3_TCD_GET_GEN(&gdesc->tcd) == tq->comp_ring.gen) { + /* Prevent any &gdesc->tcd field from being (speculatively) + * read before (&gdesc->tcd)->gen is read. + */ + dma_rmb(); + completed += vmxnet3_unmap_pkt(VMXNET3_TCD_GET_TXIDX( &gdesc->tcd), tq, adapter->pdev, adapter); @@ -1103,6 +1108,11 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq, gdesc->txd.tci = skb_vlan_tag_get(skb); } + /* Ensure that the write to (&gdesc->txd)->gen will be observed after + * all other writes to &gdesc->txd. + */ + dma_wmb(); + /* finally flips the GEN bit of the SOP desc. */ gdesc->dword[2] = cpu_to_le32(le32_to_cpu(gdesc->dword[2]) ^ VMXNET3_TXD_GEN); @@ -1298,6 +1308,12 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq, */ break; } + + /* Prevent any rcd field from being (speculatively) read before + * rcd->gen is read. + */ + dma_rmb(); + BUG_ON(rcd->rqID != rq->qid && rcd->rqID != rq->qid2 && rcd->rqID != rq->dataRingQid); idx = rcd->rxdIdx; @@ -1528,6 +1544,12 @@ rcd_done: ring->next2comp = idx; num_to_alloc = vmxnet3_cmd_ring_desc_avail(ring); ring = rq->rx_ring + ring_idx; + + /* Ensure that the writes to rxd->gen bits will be observed + * after all other writes to rxd objects. + */ + dma_wmb(); + while (num_to_alloc) { vmxnet3_getRxDesc(rxd, &ring->base[ring->next2fill].rxd, &rxCmdDesc); @@ -2688,7 +2710,7 @@ vmxnet3_set_mac_addr(struct net_device *netdev, void *p) /* ==================== initialization and cleanup routines ============ */ static int -vmxnet3_alloc_pci_resources(struct vmxnet3_adapter *adapter, bool *dma64) +vmxnet3_alloc_pci_resources(struct vmxnet3_adapter *adapter) { int err; unsigned long mmio_start, mmio_len; @@ -2700,30 +2722,12 @@ vmxnet3_alloc_pci_resources(struct vmxnet3_adapter *adapter, bool *dma64) return err; } - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) == 0) { - if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) { - dev_err(&pdev->dev, - "pci_set_consistent_dma_mask failed\n"); - err = -EIO; - goto err_set_mask; - } - *dma64 = true; - } else { - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) { - dev_err(&pdev->dev, - "pci_set_dma_mask failed\n"); - err = -EIO; - goto err_set_mask; - } - *dma64 = false; - } - err = pci_request_selected_regions(pdev, (1 << 2) - 1, vmxnet3_driver_name); if (err) { dev_err(&pdev->dev, "Failed to request region for adapter: error %d\n", err); - goto err_set_mask; + goto err_enable_device; } pci_set_master(pdev); @@ -2751,7 +2755,7 @@ err_bar1: iounmap(adapter->hw_addr0); err_ioremap: pci_release_selected_regions(pdev, (1 << 2) - 1); -err_set_mask: +err_enable_device: pci_disable_device(pdev); return err; } @@ -3254,7 +3258,7 @@ vmxnet3_probe_device(struct pci_dev *pdev, #endif }; int err; - bool dma64 = false; /* stupid gcc */ + bool dma64; u32 ver; struct net_device *netdev; struct vmxnet3_adapter *adapter; @@ -3300,6 +3304,24 @@ vmxnet3_probe_device(struct pci_dev *pdev, adapter->rx_ring_size = VMXNET3_DEF_RX_RING_SIZE; adapter->rx_ring2_size = VMXNET3_DEF_RX_RING2_SIZE; + if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) == 0) { + if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) { + dev_err(&pdev->dev, + "pci_set_consistent_dma_mask failed\n"); + err = -EIO; + goto err_set_mask; + } + dma64 = true; + } else { + if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) { + dev_err(&pdev->dev, + "pci_set_dma_mask failed\n"); + err = -EIO; + goto err_set_mask; + } + dma64 = false; + } + spin_lock_init(&adapter->cmd_lock); adapter->adapter_pa = dma_map_single(&adapter->pdev->dev, adapter, sizeof(struct vmxnet3_adapter), @@ -3307,7 +3329,7 @@ vmxnet3_probe_device(struct pci_dev *pdev, if (dma_mapping_error(&adapter->pdev->dev, adapter->adapter_pa)) { dev_err(&pdev->dev, "Failed to map dma\n"); err = -EFAULT; - goto err_dma_map; + goto err_set_mask; } adapter->shared = dma_alloc_coherent( &adapter->pdev->dev, @@ -3358,7 +3380,7 @@ vmxnet3_probe_device(struct pci_dev *pdev, } #endif /* VMXNET3_RSS */ - err = vmxnet3_alloc_pci_resources(adapter, &dma64); + err = vmxnet3_alloc_pci_resources(adapter); if (err < 0) goto err_alloc_pci; @@ -3504,7 +3526,7 @@ err_alloc_queue_desc: err_alloc_shared: dma_unmap_single(&adapter->pdev->dev, adapter->adapter_pa, sizeof(struct vmxnet3_adapter), PCI_DMA_TODEVICE); -err_dma_map: +err_set_mask: free_netdev(netdev); return err; } diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h index a3326463b71f..a2c554f8a61b 100644 --- a/drivers/net/vmxnet3/vmxnet3_int.h +++ b/drivers/net/vmxnet3/vmxnet3_int.h @@ -69,10 +69,12 @@ /* * Version numbers */ -#define VMXNET3_DRIVER_VERSION_STRING "1.4.14.0-k" +#define VMXNET3_DRIVER_VERSION_STRING "1.4.16.0-k" -/* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */ -#define VMXNET3_DRIVER_VERSION_NUM 0x01040e00 +/* Each byte of this 32-bit integer encodes a version number in + * VMXNET3_DRIVER_VERSION_STRING. + */ +#define VMXNET3_DRIVER_VERSION_NUM 0x01041000 #if defined(CONFIG_PCI_MSI) /* RSS only makes sense if MSI-X is supported. */ diff --git a/drivers/net/wireless/atmel/atmel.c b/drivers/net/wireless/atmel/atmel.c index d122386c382b..b01dc34d55af 100644 --- a/drivers/net/wireless/atmel/atmel.c +++ b/drivers/net/wireless/atmel/atmel.c @@ -1482,18 +1482,6 @@ static int atmel_proc_show(struct seq_file *m, void *v) return 0; } -static int atmel_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, atmel_proc_show, PDE_DATA(inode)); -} - -static const struct file_operations atmel_proc_fops = { - .open = atmel_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static const struct net_device_ops atmel_netdev_ops = { .ndo_open = atmel_open, .ndo_stop = atmel_close, @@ -1614,7 +1602,8 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port, netif_carrier_off(dev); - if (!proc_create_data("driver/atmel", 0, NULL, &atmel_proc_fops, priv)) + if (!proc_create_single_data("driver/atmel", 0, NULL, atmel_proc_show, + priv)) printk(KERN_WARNING "atmel: unable to create /proc entry.\n"); printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %pM\n", diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index f8a0234d332c..5517ea4c2aa0 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -1590,14 +1590,13 @@ static void iwl_pcie_set_interrupt_capa(struct pci_dev *pdev, struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - int max_irqs, num_irqs, i, ret, nr_online_cpus; + int max_irqs, num_irqs, i, ret; u16 pci_cmd; if (!trans->cfg->mq_rx_supported) goto enable_msi; - nr_online_cpus = num_online_cpus(); - max_irqs = min_t(u32, nr_online_cpus + 2, IWL_MAX_RX_HW_QUEUES); + max_irqs = min_t(u32, num_online_cpus() + 2, IWL_MAX_RX_HW_QUEUES); for (i = 0; i < max_irqs; i++) trans_pcie->msix_entries[i].entry = i; @@ -1623,16 +1622,17 @@ static void iwl_pcie_set_interrupt_capa(struct pci_dev *pdev, * Two interrupts less: non rx causes shared with FBQ and RSS. * More than two interrupts: we will use fewer RSS queues. */ - if (num_irqs <= nr_online_cpus) { + if (num_irqs <= max_irqs - 2) { trans_pcie->trans->num_rx_queues = num_irqs + 1; trans_pcie->shared_vec_mask = IWL_SHARED_IRQ_NON_RX | IWL_SHARED_IRQ_FIRST_RSS; - } else if (num_irqs == nr_online_cpus + 1) { + } else if (num_irqs == max_irqs - 1) { trans_pcie->trans->num_rx_queues = num_irqs; trans_pcie->shared_vec_mask = IWL_SHARED_IRQ_NON_RX; } else { trans_pcie->trans->num_rx_queues = num_irqs - 1; } + WARN_ON(trans_pcie->trans->num_rx_queues > IWL_MAX_RX_HW_QUEUES); trans_pcie->alloc_vecs = num_irqs; trans_pcie->msix_enabled = true; diff --git a/drivers/net/wireless/intersil/hostap/hostap_ap.c b/drivers/net/wireless/intersil/hostap/hostap_ap.c index b4dfe1893d18..d1884b8913e7 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_ap.c +++ b/drivers/net/wireless/intersil/hostap/hostap_ap.c @@ -69,7 +69,7 @@ static void prism2_send_mgmt(struct net_device *dev, #ifndef PRISM2_NO_PROCFS_DEBUG static int ap_debug_proc_show(struct seq_file *m, void *v) { - struct ap_data *ap = m->private; + struct ap_data *ap = PDE_DATA(file_inode(m->file)); seq_printf(m, "BridgedUnicastFrames=%u\n", ap->bridged_unicast); seq_printf(m, "BridgedMulticastFrames=%u\n", ap->bridged_multicast); @@ -81,18 +81,6 @@ static int ap_debug_proc_show(struct seq_file *m, void *v) seq_printf(m, "tx_drop_nonassoc=%u\n", ap->tx_drop_nonassoc); return 0; } - -static int ap_debug_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, ap_debug_proc_show, PDE_DATA(inode)); -} - -static const struct file_operations ap_debug_proc_fops = { - .open = ap_debug_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; #endif /* PRISM2_NO_PROCFS_DEBUG */ @@ -333,7 +321,7 @@ void hostap_deauth_all_stas(struct net_device *dev, struct ap_data *ap, static int ap_control_proc_show(struct seq_file *m, void *v) { - struct ap_data *ap = m->private; + struct ap_data *ap = PDE_DATA(file_inode(m->file)); char *policy_txt; struct mac_entry *entry; @@ -365,20 +353,20 @@ static int ap_control_proc_show(struct seq_file *m, void *v) static void *ap_control_proc_start(struct seq_file *m, loff_t *_pos) { - struct ap_data *ap = m->private; + struct ap_data *ap = PDE_DATA(file_inode(m->file)); spin_lock_bh(&ap->mac_restrictions.lock); return seq_list_start_head(&ap->mac_restrictions.mac_list, *_pos); } static void *ap_control_proc_next(struct seq_file *m, void *v, loff_t *_pos) { - struct ap_data *ap = m->private; + struct ap_data *ap = PDE_DATA(file_inode(m->file)); return seq_list_next(v, &ap->mac_restrictions.mac_list, _pos); } static void ap_control_proc_stop(struct seq_file *m, void *v) { - struct ap_data *ap = m->private; + struct ap_data *ap = PDE_DATA(file_inode(m->file)); spin_unlock_bh(&ap->mac_restrictions.lock); } @@ -389,24 +377,6 @@ static const struct seq_operations ap_control_proc_seqops = { .show = ap_control_proc_show, }; -static int ap_control_proc_open(struct inode *inode, struct file *file) -{ - int ret = seq_open(file, &ap_control_proc_seqops); - if (ret == 0) { - struct seq_file *m = file->private_data; - m->private = PDE_DATA(inode); - } - return ret; -} - -static const struct file_operations ap_control_proc_fops = { - .open = ap_control_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - - int ap_control_add_mac(struct mac_restrictions *mac_restrictions, u8 *mac) { struct mac_entry *entry; @@ -585,20 +555,20 @@ static int prism2_ap_proc_show(struct seq_file *m, void *v) static void *prism2_ap_proc_start(struct seq_file *m, loff_t *_pos) { - struct ap_data *ap = m->private; + struct ap_data *ap = PDE_DATA(file_inode(m->file)); spin_lock_bh(&ap->sta_table_lock); return seq_list_start_head(&ap->sta_list, *_pos); } static void *prism2_ap_proc_next(struct seq_file *m, void *v, loff_t *_pos) { - struct ap_data *ap = m->private; + struct ap_data *ap = PDE_DATA(file_inode(m->file)); return seq_list_next(v, &ap->sta_list, _pos); } static void prism2_ap_proc_stop(struct seq_file *m, void *v) { - struct ap_data *ap = m->private; + struct ap_data *ap = PDE_DATA(file_inode(m->file)); spin_unlock_bh(&ap->sta_table_lock); } @@ -608,23 +578,6 @@ static const struct seq_operations prism2_ap_proc_seqops = { .stop = prism2_ap_proc_stop, .show = prism2_ap_proc_show, }; - -static int prism2_ap_proc_open(struct inode *inode, struct file *file) -{ - int ret = seq_open(file, &prism2_ap_proc_seqops); - if (ret == 0) { - struct seq_file *m = file->private_data; - m->private = PDE_DATA(inode); - } - return ret; -} - -static const struct file_operations prism2_ap_proc_fops = { - .open = prism2_ap_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ @@ -896,12 +849,13 @@ void hostap_init_ap_proc(local_info_t *local) return; #ifndef PRISM2_NO_PROCFS_DEBUG - proc_create_data("ap_debug", 0, ap->proc, &ap_debug_proc_fops, ap); + proc_create_single_data("ap_debug", 0, ap->proc, ap_debug_proc_show, ap); #endif /* PRISM2_NO_PROCFS_DEBUG */ #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT - proc_create_data("ap_control", 0, ap->proc, &ap_control_proc_fops, ap); - proc_create_data("ap", 0, ap->proc, &prism2_ap_proc_fops, ap); + proc_create_seq_data("ap_control", 0, ap->proc, &ap_control_proc_seqops, + ap); + proc_create_seq_data("ap", 0, ap->proc, &prism2_ap_proc_seqops, ap); #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ } @@ -1106,18 +1060,6 @@ static int prism2_sta_proc_show(struct seq_file *m, void *v) return 0; } -static int prism2_sta_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, prism2_sta_proc_show, PDE_DATA(inode)); -} - -static const struct file_operations prism2_sta_proc_fops = { - .open = prism2_sta_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static void handle_add_proc_queue(struct work_struct *work) { struct ap_data *ap = container_of(work, struct ap_data, @@ -1138,9 +1080,9 @@ static void handle_add_proc_queue(struct work_struct *work) if (sta) { sprintf(name, "%pM", sta->addr); - sta->proc = proc_create_data( + sta->proc = proc_create_single_data( name, 0, ap->proc, - &prism2_sta_proc_fops, sta); + prism2_sta_proc_show, sta); atomic_dec(&sta->users); } diff --git a/drivers/net/wireless/intersil/hostap/hostap_hw.c b/drivers/net/wireless/intersil/hostap/hostap_hw.c index 5c4a17a18968..2720aa39f530 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_hw.c +++ b/drivers/net/wireless/intersil/hostap/hostap_hw.c @@ -2951,19 +2951,6 @@ static int prism2_registers_proc_show(struct seq_file *m, void *v) return 0; } - -static int prism2_registers_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, prism2_registers_proc_show, PDE_DATA(inode)); -} - -static const struct file_operations prism2_registers_proc_fops = { - .open = prism2_registers_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - #endif /* PRISM2_NO_PROCFS_DEBUG */ @@ -3279,8 +3266,8 @@ static int hostap_hw_ready(struct net_device *dev) } hostap_init_proc(local); #ifndef PRISM2_NO_PROCFS_DEBUG - proc_create_data("registers", 0, local->proc, - &prism2_registers_proc_fops, local); + proc_create_single_data("registers", 0, local->proc, + prism2_registers_proc_show, local); #endif /* PRISM2_NO_PROCFS_DEBUG */ hostap_init_ap_proc(local); return 0; diff --git a/drivers/net/wireless/intersil/hostap/hostap_proc.c b/drivers/net/wireless/intersil/hostap/hostap_proc.c index d234231bf532..5b33ccab9188 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_proc.c +++ b/drivers/net/wireless/intersil/hostap/hostap_proc.c @@ -43,18 +43,6 @@ static int prism2_debug_proc_show(struct seq_file *m, void *v) return 0; } - -static int prism2_debug_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, prism2_debug_proc_show, PDE_DATA(inode)); -} - -static const struct file_operations prism2_debug_proc_fops = { - .open = prism2_debug_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; #endif /* PRISM2_NO_PROCFS_DEBUG */ @@ -95,19 +83,6 @@ static int prism2_stats_proc_show(struct seq_file *m, void *v) return 0; } -static int prism2_stats_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, prism2_stats_proc_show, PDE_DATA(inode)); -} - -static const struct file_operations prism2_stats_proc_fops = { - .open = prism2_stats_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - - static int prism2_wds_proc_show(struct seq_file *m, void *v) { struct list_head *ptr = v; @@ -122,20 +97,20 @@ static int prism2_wds_proc_show(struct seq_file *m, void *v) static void *prism2_wds_proc_start(struct seq_file *m, loff_t *_pos) { - local_info_t *local = m->private; + local_info_t *local = PDE_DATA(file_inode(m->file)); read_lock_bh(&local->iface_lock); return seq_list_start(&local->hostap_interfaces, *_pos); } static void *prism2_wds_proc_next(struct seq_file *m, void *v, loff_t *_pos) { - local_info_t *local = m->private; + local_info_t *local = PDE_DATA(file_inode(m->file)); return seq_list_next(v, &local->hostap_interfaces, _pos); } static void prism2_wds_proc_stop(struct seq_file *m, void *v) { - local_info_t *local = m->private; + local_info_t *local = PDE_DATA(file_inode(m->file)); read_unlock_bh(&local->iface_lock); } @@ -146,27 +121,9 @@ static const struct seq_operations prism2_wds_proc_seqops = { .show = prism2_wds_proc_show, }; -static int prism2_wds_proc_open(struct inode *inode, struct file *file) -{ - int ret = seq_open(file, &prism2_wds_proc_seqops); - if (ret == 0) { - struct seq_file *m = file->private_data; - m->private = PDE_DATA(inode); - } - return ret; -} - -static const struct file_operations prism2_wds_proc_fops = { - .open = prism2_wds_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - - static int prism2_bss_list_proc_show(struct seq_file *m, void *v) { - local_info_t *local = m->private; + local_info_t *local = PDE_DATA(file_inode(m->file)); struct list_head *ptr = v; struct hostap_bss_info *bss; @@ -193,20 +150,20 @@ static int prism2_bss_list_proc_show(struct seq_file *m, void *v) static void *prism2_bss_list_proc_start(struct seq_file *m, loff_t *_pos) { - local_info_t *local = m->private; + local_info_t *local = PDE_DATA(file_inode(m->file)); spin_lock_bh(&local->lock); return seq_list_start_head(&local->bss_list, *_pos); } static void *prism2_bss_list_proc_next(struct seq_file *m, void *v, loff_t *_pos) { - local_info_t *local = m->private; + local_info_t *local = PDE_DATA(file_inode(m->file)); return seq_list_next(v, &local->bss_list, _pos); } static void prism2_bss_list_proc_stop(struct seq_file *m, void *v) { - local_info_t *local = m->private; + local_info_t *local = PDE_DATA(file_inode(m->file)); spin_unlock_bh(&local->lock); } @@ -217,24 +174,6 @@ static const struct seq_operations prism2_bss_list_proc_seqops = { .show = prism2_bss_list_proc_show, }; -static int prism2_bss_list_proc_open(struct inode *inode, struct file *file) -{ - int ret = seq_open(file, &prism2_bss_list_proc_seqops); - if (ret == 0) { - struct seq_file *m = file->private_data; - m->private = PDE_DATA(inode); - } - return ret; -} - -static const struct file_operations prism2_bss_list_proc_fops = { - .open = prism2_bss_list_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - - static int prism2_crypt_proc_show(struct seq_file *m, void *v) { local_info_t *local = m->private; @@ -252,19 +191,6 @@ static int prism2_crypt_proc_show(struct seq_file *m, void *v) return 0; } -static int prism2_crypt_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, prism2_crypt_proc_show, PDE_DATA(inode)); -} - -static const struct file_operations prism2_crypt_proc_fops = { - .open = prism2_crypt_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - - static ssize_t prism2_pda_proc_read(struct file *file, char __user *buf, size_t count, loff_t *_pos) { @@ -342,7 +268,7 @@ static int prism2_io_debug_proc_read(char *page, char **start, off_t off, #ifndef PRISM2_NO_STATION_MODES static int prism2_scan_results_proc_show(struct seq_file *m, void *v) { - local_info_t *local = m->private; + local_info_t *local = PDE_DATA(file_inode(m->file)); unsigned long entry; int i, len; struct hfa384x_hostscan_result *scanres; @@ -392,7 +318,7 @@ static int prism2_scan_results_proc_show(struct seq_file *m, void *v) static void *prism2_scan_results_proc_start(struct seq_file *m, loff_t *_pos) { - local_info_t *local = m->private; + local_info_t *local = PDE_DATA(file_inode(m->file)); spin_lock_bh(&local->lock); /* We have a header (pos 0) + N results to show (pos 1...N) */ @@ -403,7 +329,7 @@ static void *prism2_scan_results_proc_start(struct seq_file *m, loff_t *_pos) static void *prism2_scan_results_proc_next(struct seq_file *m, void *v, loff_t *_pos) { - local_info_t *local = m->private; + local_info_t *local = PDE_DATA(file_inode(m->file)); ++*_pos; if (*_pos > local->last_scan_results_count) @@ -413,7 +339,7 @@ static void *prism2_scan_results_proc_next(struct seq_file *m, void *v, loff_t * static void prism2_scan_results_proc_stop(struct seq_file *m, void *v) { - local_info_t *local = m->private; + local_info_t *local = PDE_DATA(file_inode(m->file)); spin_unlock_bh(&local->lock); } @@ -423,25 +349,6 @@ static const struct seq_operations prism2_scan_results_proc_seqops = { .stop = prism2_scan_results_proc_stop, .show = prism2_scan_results_proc_show, }; - -static int prism2_scan_results_proc_open(struct inode *inode, struct file *file) -{ - int ret = seq_open(file, &prism2_scan_results_proc_seqops); - if (ret == 0) { - struct seq_file *m = file->private_data; - m->private = PDE_DATA(inode); - } - return ret; -} - -static const struct file_operations prism2_scan_results_proc_fops = { - .open = prism2_scan_results_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - - #endif /* PRISM2_NO_STATION_MODES */ @@ -463,29 +370,29 @@ void hostap_init_proc(local_info_t *local) } #ifndef PRISM2_NO_PROCFS_DEBUG - proc_create_data("debug", 0, local->proc, - &prism2_debug_proc_fops, local); + proc_create_single_data("debug", 0, local->proc, + prism2_debug_proc_show, local); #endif /* PRISM2_NO_PROCFS_DEBUG */ - proc_create_data("stats", 0, local->proc, - &prism2_stats_proc_fops, local); - proc_create_data("wds", 0, local->proc, - &prism2_wds_proc_fops, local); + proc_create_single_data("stats", 0, local->proc, prism2_stats_proc_show, + local); + proc_create_seq_data("wds", 0, local->proc, + &prism2_wds_proc_seqops, local); proc_create_data("pda", 0, local->proc, &prism2_pda_proc_fops, local); proc_create_data("aux_dump", 0, local->proc, local->func->read_aux_fops ?: &prism2_aux_dump_proc_fops, local); - proc_create_data("bss_list", 0, local->proc, - &prism2_bss_list_proc_fops, local); - proc_create_data("crypt", 0, local->proc, - &prism2_crypt_proc_fops, local); + proc_create_seq_data("bss_list", 0, local->proc, + &prism2_bss_list_proc_seqops, local); + proc_create_single_data("crypt", 0, local->proc, prism2_crypt_proc_show, + local); #ifdef PRISM2_IO_DEBUG - proc_create_data("io_debug", 0, local->proc, - &prism2_io_debug_proc_fops, local); + proc_create_single_data("io_debug", 0, local->proc, + prism2_debug_proc_show, local); #endif /* PRISM2_IO_DEBUG */ #ifndef PRISM2_NO_STATION_MODES - proc_create_data("scan_results", 0, local->proc, - &prism2_scan_results_proc_fops, local); + proc_create_seq_data("scan_results", 0, local->proc, + &prism2_scan_results_proc_seqops, local); #endif /* PRISM2_NO_STATION_MODES */ } diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 4a017a0d71ea..920c23e542a5 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -3340,7 +3340,7 @@ out_err: static int hwsim_dump_radio_nl(struct sk_buff *skb, struct netlink_callback *cb) { - int last_idx = cb->args[0]; + int last_idx = cb->args[0] - 1; struct mac80211_hwsim_data *data = NULL; int res = 0; void *hdr; @@ -3368,7 +3368,7 @@ static int hwsim_dump_radio_nl(struct sk_buff *skb, last_idx = data->idx; } - cb->args[0] = last_idx; + cb->args[0] = last_idx + 1; /* list changed, but no new element sent, set interrupted flag */ if (skb->len == 0 && cb->prev_seq && cb->seq != cb->prev_seq) { diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c index a6884e73d2ab..7ddee980048b 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c @@ -372,16 +372,15 @@ static void rt2x00queue_create_tx_descriptor_ht(struct rt2x00_dev *rt2x00dev, /* * Determine IFS values - * - Use TXOP_BACKOFF for probe and management frames except beacons + * - Use TXOP_BACKOFF for management frames except beacons * - Use TXOP_SIFS for fragment bursts * - Use TXOP_HTTXOP for everything else * * Note: rt2800 devices won't use CTS protection (if used) * for frames not transmitted with TXOP_HTTXOP */ - if ((ieee80211_is_mgmt(hdr->frame_control) && - !ieee80211_is_beacon(hdr->frame_control)) || - (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)) + if (ieee80211_is_mgmt(hdr->frame_control) && + !ieee80211_is_beacon(hdr->frame_control)) txdesc->u.ht.txop = TXOP_BACKOFF; else if (!(tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)) txdesc->u.ht.txop = TXOP_SIFS; diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 7f9b16b97ea3..a7e0a17aa7e8 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -2663,19 +2663,6 @@ static int ray_cs_proc_show(struct seq_file *m, void *v) } return 0; } - -static int ray_cs_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, ray_cs_proc_show, NULL); -} - -static const struct file_operations ray_cs_proc_fops = { - .owner = THIS_MODULE, - .open = ray_cs_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; #endif /*===========================================================================*/ static int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type) @@ -2814,7 +2801,7 @@ static int __init init_ray_cs(void) #ifdef CONFIG_PROC_FS proc_mkdir("driver/ray_cs", NULL); - proc_create("driver/ray_cs/ray_cs", 0, NULL, &ray_cs_proc_fops); + proc_create_single("driver/ray_cs/ray_cs", 0, NULL, ray_cs_proc_show); proc_create("driver/ray_cs/essid", 0200, NULL, &ray_cs_essid_proc_fops); proc_create_data("driver/ray_cs/net_type", 0200, NULL, &int_proc_fops, &net_type); diff --git a/drivers/nubus/proc.c b/drivers/nubus/proc.c index c2e5a7e6bd3e..88e1f9a0faaf 100644 --- a/drivers/nubus/proc.c +++ b/drivers/nubus/proc.c @@ -45,18 +45,6 @@ nubus_devices_proc_show(struct seq_file *m, void *v) return 0; } -static int nubus_devices_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, nubus_devices_proc_show, NULL); -} - -static const struct file_operations nubus_devices_proc_fops = { - .open = nubus_devices_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static struct proc_dir_entry *proc_bus_nubus_dir; /* @@ -149,18 +137,6 @@ static int nubus_proc_rsrc_show(struct seq_file *m, void *v) return 0; } -static int nubus_proc_rsrc_open(struct inode *inode, struct file *file) -{ - return single_open(file, nubus_proc_rsrc_show, inode); -} - -static const struct file_operations nubus_proc_rsrc_fops = { - .open = nubus_proc_rsrc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - void nubus_proc_add_rsrc_mem(struct proc_dir_entry *procdir, const struct nubus_dirent *ent, unsigned int size) @@ -176,8 +152,8 @@ void nubus_proc_add_rsrc_mem(struct proc_dir_entry *procdir, pde_data = nubus_proc_alloc_pde_data(nubus_dirptr(ent), size); else pde_data = NULL; - proc_create_data(name, S_IFREG | 0444, procdir, - &nubus_proc_rsrc_fops, pde_data); + proc_create_single_data(name, S_IFREG | 0444, procdir, + nubus_proc_rsrc_show, pde_data); } void nubus_proc_add_rsrc(struct proc_dir_entry *procdir, @@ -190,32 +166,21 @@ void nubus_proc_add_rsrc(struct proc_dir_entry *procdir, return; snprintf(name, sizeof(name), "%x", ent->type); - proc_create_data(name, S_IFREG | 0444, procdir, - &nubus_proc_rsrc_fops, - nubus_proc_alloc_pde_data(data, 0)); + proc_create_single_data(name, S_IFREG | 0444, procdir, + nubus_proc_rsrc_show, + nubus_proc_alloc_pde_data(data, 0)); } /* * /proc/nubus stuff */ -static int nubus_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, nubus_proc_show, NULL); -} - -static const struct file_operations nubus_proc_fops = { - .open = nubus_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - void __init nubus_proc_init(void) { - proc_create("nubus", 0, NULL, &nubus_proc_fops); + proc_create_single("nubus", 0, NULL, nubus_proc_show); proc_bus_nubus_dir = proc_mkdir("bus/nubus", NULL); if (!proc_bus_nubus_dir) return; - proc_create("devices", 0, proc_bus_nubus_dir, &nubus_devices_proc_fops); + proc_create_single("devices", 0, proc_bus_nubus_dir, + nubus_devices_proc_show); } diff --git a/drivers/nvdimm/claim.c b/drivers/nvdimm/claim.c index 30852270484f..2e96b34bc936 100644 --- a/drivers/nvdimm/claim.c +++ b/drivers/nvdimm/claim.c @@ -276,7 +276,8 @@ static int nsio_rw_bytes(struct nd_namespace_common *ndns, if (rw == READ) { if (unlikely(is_bad_pmem(&nsio->bb, sector, sz_align))) return -EIO; - return memcpy_mcsafe(buf, nsio->addr + offset, size); + if (memcpy_mcsafe(buf, nsio->addr + offset, size) != 0) + return -EIO; } if (unlikely(is_bad_pmem(&nsio->bb, sector, sz_align))) { diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index 9d714926ecf5..e023d6aa22b5 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c @@ -101,15 +101,15 @@ static blk_status_t read_pmem(struct page *page, unsigned int off, void *pmem_addr, unsigned int len) { unsigned int chunk; - int rc; + unsigned long rem; void *mem; while (len) { mem = kmap_atomic(page); chunk = min_t(unsigned int, len, PAGE_SIZE); - rc = memcpy_mcsafe(mem + off, pmem_addr, chunk); + rem = memcpy_mcsafe(mem + off, pmem_addr, chunk); kunmap_atomic(mem); - if (rc) + if (rem) return BLK_STS_IOERR; len -= chunk; off = 0; diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 99b857e5a7a9..c8b30067b6ae 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -101,6 +101,15 @@ static void nvme_ns_remove(struct nvme_ns *ns); static int nvme_revalidate_disk(struct gendisk *disk); static void nvme_put_subsystem(struct nvme_subsystem *subsys); +static void nvme_queue_scan(struct nvme_ctrl *ctrl) +{ + /* + * Only new queue scan work when admin and IO queues are both alive + */ + if (ctrl->state == NVME_CTRL_LIVE) + queue_work(nvme_wq, &ctrl->scan_work); +} + int nvme_reset_ctrl(struct nvme_ctrl *ctrl) { if (!nvme_change_ctrl_state(ctrl, NVME_CTRL_RESETTING)) @@ -244,9 +253,6 @@ EXPORT_SYMBOL_GPL(nvme_complete_rq); void nvme_cancel_request(struct request *req, void *data, bool reserved) { - if (!blk_mq_request_started(req)) - return; - dev_dbg_ratelimited(((struct nvme_ctrl *) data)->device, "Cancelling I/O %d", req->tag); @@ -351,7 +357,7 @@ static void nvme_free_ns_head(struct kref *ref) nvme_mpath_remove_disk(head); ida_simple_remove(&head->subsys->ns_ida, head->instance); list_del_init(&head->entry); - cleanup_srcu_struct(&head->srcu); + cleanup_srcu_struct_quiesced(&head->srcu); nvme_put_subsystem(head->subsys); kfree(head); } @@ -1033,6 +1039,21 @@ int nvme_set_queue_count(struct nvme_ctrl *ctrl, int *count) } EXPORT_SYMBOL_GPL(nvme_set_queue_count); +#define NVME_AEN_SUPPORTED \ + (NVME_AEN_CFG_NS_ATTR | NVME_AEN_CFG_FW_ACT) + +static void nvme_enable_aen(struct nvme_ctrl *ctrl) +{ + u32 result; + int status; + + status = nvme_set_features(ctrl, NVME_FEAT_ASYNC_EVENT, + ctrl->oaes & NVME_AEN_SUPPORTED, NULL, 0, &result); + if (status) + dev_warn(ctrl->device, "Failed to configure AEN (cfg %x)\n", + ctrl->oaes & NVME_AEN_SUPPORTED); +} + static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio) { struct nvme_user_io io; @@ -1351,13 +1372,19 @@ static void nvme_set_chunk_size(struct nvme_ns *ns) blk_queue_chunk_sectors(ns->queue, rounddown_pow_of_two(chunk_size)); } -static void nvme_config_discard(struct nvme_ctrl *ctrl, - unsigned stream_alignment, struct request_queue *queue) +static void nvme_config_discard(struct nvme_ns *ns) { + struct nvme_ctrl *ctrl = ns->ctrl; + struct request_queue *queue = ns->queue; u32 size = queue_logical_block_size(queue); - if (stream_alignment) - size *= stream_alignment; + if (!(ctrl->oncs & NVME_CTRL_ONCS_DSM)) { + blk_queue_flag_clear(QUEUE_FLAG_DISCARD, queue); + return; + } + + if (ctrl->nr_streams && ns->sws && ns->sgs) + size *= ns->sws * ns->sgs; BUILD_BUG_ON(PAGE_SIZE / sizeof(struct nvme_dsm_range) < NVME_DSM_MAX_RANGES); @@ -1365,9 +1392,12 @@ static void nvme_config_discard(struct nvme_ctrl *ctrl, queue->limits.discard_alignment = 0; queue->limits.discard_granularity = size; + /* If discard is already enabled, don't reset queue limits */ + if (blk_queue_flag_test_and_set(QUEUE_FLAG_DISCARD, queue)) + return; + blk_queue_max_discard_sectors(queue, UINT_MAX); blk_queue_max_discard_segments(queue, NVME_DSM_MAX_RANGES); - blk_queue_flag_set(QUEUE_FLAG_DISCARD, queue); if (ctrl->quirks & NVME_QUIRK_DEALLOCATE_ZEROES) blk_queue_max_write_zeroes_sectors(queue, UINT_MAX); @@ -1411,10 +1441,6 @@ static void nvme_update_disk_info(struct gendisk *disk, { sector_t capacity = le64_to_cpup(&id->nsze) << (ns->lba_shift - 9); unsigned short bs = 1 << ns->lba_shift; - unsigned stream_alignment = 0; - - if (ns->ctrl->nr_streams && ns->sws && ns->sgs) - stream_alignment = ns->sws * ns->sgs; blk_mq_freeze_queue(disk->queue); blk_integrity_unregister(disk); @@ -1428,10 +1454,9 @@ static void nvme_update_disk_info(struct gendisk *disk, nvme_init_integrity(disk, ns->ms, ns->pi_type); if (ns->ms && !nvme_ns_has_pi(ns) && !blk_get_integrity(disk)) capacity = 0; - set_capacity(disk, capacity); - if (ns->ctrl->oncs & NVME_CTRL_ONCS_DSM) - nvme_config_discard(ns->ctrl, stream_alignment, disk->queue); + set_capacity(disk, capacity); + nvme_config_discard(ns); blk_mq_unfreeze_queue(disk->queue); } @@ -1447,8 +1472,8 @@ static void __nvme_revalidate_disk(struct gendisk *disk, struct nvme_id_ns *id) if (ns->lba_shift == 0) ns->lba_shift = 9; ns->noiob = le16_to_cpu(id->noiob); - ns->ext = ns->ms && (id->flbas & NVME_NS_FLBAS_META_EXT); ns->ms = le16_to_cpu(id->lbaf[id->flbas & NVME_NS_FLBAS_LBA_MASK].ms); + ns->ext = ns->ms && (id->flbas & NVME_NS_FLBAS_META_EXT); /* the PI implementation requires metadata equal t10 pi tuple size */ if (ns->ms == sizeof(struct t10_pi_tuple)) ns->pi_type = id->dps & NVME_NS_DPS_PI_MASK; @@ -1577,7 +1602,7 @@ static int nvme_pr_reserve(struct block_device *bdev, u64 key, static int nvme_pr_preempt(struct block_device *bdev, u64 old, u64 new, enum pr_type type, bool abort) { - u32 cdw10 = nvme_pr_type(type) << 8 | abort ? 2 : 1; + u32 cdw10 = nvme_pr_type(type) << 8 | (abort ? 2 : 1); return nvme_pr_command(bdev, cdw10, old, new, nvme_cmd_resv_acquire); } @@ -1589,7 +1614,7 @@ static int nvme_pr_clear(struct block_device *bdev, u64 key) static int nvme_pr_release(struct block_device *bdev, u64 key, enum pr_type type) { - u32 cdw10 = nvme_pr_type(type) << 8 | key ? 1 << 3 : 0; + u32 cdw10 = nvme_pr_type(type) << 8 | (key ? 1 << 3 : 0); return nvme_pr_command(bdev, cdw10, key, 0, nvme_cmd_resv_release); } @@ -2183,7 +2208,8 @@ static int nvme_init_subsystem(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id) * Verify that the subsystem actually supports multiple * controllers, else bail out. */ - if (nvme_active_ctrls(found) && !(id->cmic & (1 << 1))) { + if (!ctrl->opts->discovery_nqn && + nvme_active_ctrls(found) && !(id->cmic & (1 << 1))) { dev_err(ctrl->device, "ignoring ctrl due to duplicate subnqn (%s).\n", found->subnqn); @@ -2314,7 +2340,7 @@ int nvme_init_identify(struct nvme_ctrl *ctrl) if (id->lpa & NVME_CTRL_LPA_CMD_EFFECTS_LOG) { ret = nvme_get_effects_log(ctrl); if (ret < 0) - return ret; + goto out_free; } if (!ctrl->identified) { @@ -2345,6 +2371,7 @@ int nvme_init_identify(struct nvme_ctrl *ctrl) ctrl->oacs = le16_to_cpu(id->oacs); ctrl->oncs = le16_to_cpup(&id->oncs); + ctrl->oaes = le32_to_cpu(id->oaes); atomic_set(&ctrl->abort_limit, id->acl + 1); ctrl->vwc = id->vwc; ctrl->cntlid = le16_to_cpup(&id->cntlid); @@ -3170,6 +3197,42 @@ static void nvme_scan_ns_sequential(struct nvme_ctrl *ctrl, unsigned nn) nvme_remove_invalid_namespaces(ctrl, nn); } +static bool nvme_scan_changed_ns_log(struct nvme_ctrl *ctrl) +{ + size_t log_size = NVME_MAX_CHANGED_NAMESPACES * sizeof(__le32); + __le32 *log; + int error, i; + bool ret = false; + + log = kzalloc(log_size, GFP_KERNEL); + if (!log) + return false; + + error = nvme_get_log(ctrl, NVME_LOG_CHANGED_NS, log, log_size); + if (error) { + dev_warn(ctrl->device, + "reading changed ns log failed: %d\n", error); + goto out_free_log; + } + + if (log[0] == cpu_to_le32(0xffffffff)) + goto out_free_log; + + for (i = 0; i < NVME_MAX_CHANGED_NAMESPACES; i++) { + u32 nsid = le32_to_cpu(log[i]); + + if (nsid == 0) + break; + dev_info(ctrl->device, "rescanning namespace %d.\n", nsid); + nvme_validate_ns(ctrl, nsid); + } + ret = true; + +out_free_log: + kfree(log); + return ret; +} + static void nvme_scan_work(struct work_struct *work) { struct nvme_ctrl *ctrl = @@ -3182,6 +3245,12 @@ static void nvme_scan_work(struct work_struct *work) WARN_ON_ONCE(!ctrl->tagset); + if (test_and_clear_bit(EVENT_NS_CHANGED, &ctrl->events)) { + if (nvme_scan_changed_ns_log(ctrl)) + goto out_sort_namespaces; + dev_info(ctrl->device, "rescanning namespaces.\n"); + } + if (nvme_identify_ctrl(ctrl, &id)) return; @@ -3189,26 +3258,17 @@ static void nvme_scan_work(struct work_struct *work) if (ctrl->vs >= NVME_VS(1, 1, 0) && !(ctrl->quirks & NVME_QUIRK_IDENTIFY_CNS)) { if (!nvme_scan_ns_list(ctrl, nn)) - goto done; + goto out_free_id; } nvme_scan_ns_sequential(ctrl, nn); - done: +out_free_id: + kfree(id); +out_sort_namespaces: down_write(&ctrl->namespaces_rwsem); list_sort(NULL, &ctrl->namespaces, ns_cmp); up_write(&ctrl->namespaces_rwsem); - kfree(id); } -void nvme_queue_scan(struct nvme_ctrl *ctrl) -{ - /* - * Only new queue scan work when admin and IO queues are both alive - */ - if (ctrl->state == NVME_CTRL_LIVE) - queue_work(nvme_wq, &ctrl->scan_work); -} -EXPORT_SYMBOL_GPL(nvme_queue_scan); - /* * This function iterates the namespace list unlocked to allow recovery from * controller failure. It is up to the caller to ensure the namespace list is @@ -3322,8 +3382,23 @@ static void nvme_fw_act_work(struct work_struct *work) nvme_get_fw_slot_info(ctrl); } +static void nvme_handle_aen_notice(struct nvme_ctrl *ctrl, u32 result) +{ + switch ((result & 0xff00) >> 8) { + case NVME_AER_NOTICE_NS_CHANGED: + set_bit(EVENT_NS_CHANGED, &ctrl->events); + nvme_queue_scan(ctrl); + break; + case NVME_AER_NOTICE_FW_ACT_STARTING: + queue_work(nvme_wq, &ctrl->fw_act_work); + break; + default: + dev_warn(ctrl->device, "async event result %08x\n", result); + } +} + void nvme_complete_async_event(struct nvme_ctrl *ctrl, __le16 status, - union nvme_result *res) + volatile union nvme_result *res) { u32 result = le32_to_cpu(res->u32); @@ -3331,6 +3406,9 @@ void nvme_complete_async_event(struct nvme_ctrl *ctrl, __le16 status, return; switch (result & 0x7) { + case NVME_AER_NOTICE: + nvme_handle_aen_notice(ctrl, result); + break; case NVME_AER_ERROR: case NVME_AER_SMART: case NVME_AER_CSS: @@ -3340,18 +3418,6 @@ void nvme_complete_async_event(struct nvme_ctrl *ctrl, __le16 status, default: break; } - - switch (result & 0xff07) { - case NVME_AER_NOTICE_NS_CHANGED: - dev_info(ctrl->device, "rescanning\n"); - nvme_queue_scan(ctrl); - break; - case NVME_AER_NOTICE_FW_ACT_STARTING: - queue_work(nvme_wq, &ctrl->fw_act_work); - break; - default: - dev_warn(ctrl->device, "async event result %08x\n", result); - } queue_work(nvme_wq, &ctrl->async_event_work); } EXPORT_SYMBOL_GPL(nvme_complete_async_event); @@ -3374,6 +3440,7 @@ void nvme_start_ctrl(struct nvme_ctrl *ctrl) if (ctrl->queue_count > 1) { nvme_queue_scan(ctrl); + nvme_enable_aen(ctrl); queue_work(nvme_wq, &ctrl->async_event_work); nvme_start_queues(ctrl); } diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c index 7ae732a77fe8..5f5f7067c41d 100644 --- a/drivers/nvme/host/fabrics.c +++ b/drivers/nvme/host/fabrics.c @@ -57,7 +57,7 @@ static struct nvmf_host *nvmf_host_add(const char *hostnqn) goto out_unlock; kref_init(&host->ref); - memcpy(host->nqn, hostnqn, NVMF_NQN_SIZE); + strlcpy(host->nqn, hostnqn, NVMF_NQN_SIZE); list_add_tail(&host->list, &nvmf_hosts); out_unlock: @@ -545,71 +545,54 @@ blk_status_t nvmf_check_if_ready(struct nvme_ctrl *ctrl, struct request *rq, return BLK_STS_OK; switch (ctrl->state) { - case NVME_CTRL_DELETING: - goto reject_io; - case NVME_CTRL_NEW: case NVME_CTRL_CONNECTING: + case NVME_CTRL_DELETING: + /* + * This is the case of starting a new or deleting an association + * but connectivity was lost before it was fully created or torn + * down. We need to error the commands used to initialize the + * controller so the reconnect can go into a retry attempt. The + * commands should all be marked REQ_FAILFAST_DRIVER, which will + * hit the reject path below. Anything else will be queued while + * the state settles. + */ if (!is_connected) - /* - * This is the case of starting a new - * association but connectivity was lost - * before it was fully created. We need to - * error the commands used to initialize the - * controller so the reconnect can go into a - * retry attempt. The commands should all be - * marked REQ_FAILFAST_DRIVER, which will hit - * the reject path below. Anything else will - * be queued while the state settles. - */ - goto reject_or_queue_io; - - if ((queue_live && - !(nvme_req(rq)->flags & NVME_REQ_USERCMD)) || - (!queue_live && blk_rq_is_passthrough(rq) && - cmd->common.opcode == nvme_fabrics_command && - cmd->fabrics.fctype == nvme_fabrics_type_connect)) - /* - * If queue is live, allow only commands that - * are internally generated pass through. These - * are commands on the admin queue to initialize - * the controller. This will reject any ioctl - * admin cmds received while initializing. - * - * If the queue is not live, allow only a - * connect command. This will reject any ioctl - * admin cmd as well as initialization commands - * if the controller reverted the queue to non-live. - */ + break; + + /* + * If queue is live, allow only commands that are internally + * generated pass through. These are commands on the admin + * queue to initialize the controller. This will reject any + * ioctl admin cmds received while initializing. + */ + if (queue_live && !(nvme_req(rq)->flags & NVME_REQ_USERCMD)) return BLK_STS_OK; /* - * fall-thru to the reject_or_queue_io clause + * If the queue is not live, allow only a connect command. This + * will reject any ioctl admin cmd as well as initialization + * commands if the controller reverted the queue to non-live. */ + if (!queue_live && blk_rq_is_passthrough(rq) && + cmd->common.opcode == nvme_fabrics_command && + cmd->fabrics.fctype == nvme_fabrics_type_connect) + return BLK_STS_OK; break; - - /* these cases fall-thru - * case NVME_CTRL_LIVE: - * case NVME_CTRL_RESETTING: - */ default: break; } -reject_or_queue_io: /* - * Any other new io is something we're not in a state to send - * to the device. Default action is to busy it and retry it - * after the controller state is recovered. However, anything - * marked for failfast or nvme multipath is immediately failed. - * Note: commands used to initialize the controller will be - * marked for failfast. + * Any other new io is something we're not in a state to send to the + * device. Default action is to busy it and retry it after the + * controller state is recovered. However, anything marked for failfast + * or nvme multipath is immediately failed. Note: commands used to + * initialize the controller will be marked for failfast. * Note: nvme cli/ioctl commands are marked for failfast. */ if (!blk_noretry_request(rq) && !(rq->cmd_flags & REQ_NVME_MPATH)) return BLK_STS_RESOURCE; - -reject_io: nvme_req(rq)->status = NVME_SC_ABORT_REQ; return BLK_STS_IOERR; } @@ -689,10 +672,6 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts, opts->discovery_nqn = !(strcmp(opts->subsysnqn, NVME_DISC_SUBSYS_NAME)); - if (opts->discovery_nqn) { - opts->kato = 0; - opts->nr_io_queues = 0; - } break; case NVMF_OPT_TRADDR: p = match_strdup(args); @@ -851,6 +830,11 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts, } } + if (opts->discovery_nqn) { + opts->kato = 0; + opts->nr_io_queues = 0; + opts->duplicate_connect = true; + } if (ctrl_loss_tmo < 0) opts->max_reconnects = -1; else @@ -983,16 +967,6 @@ nvmf_create_ctrl(struct device *dev, const char *buf, size_t count) goto out_module_put; } - if (strcmp(ctrl->subsys->subnqn, opts->subsysnqn)) { - dev_warn(ctrl->device, - "controller returned incorrect NQN: \"%s\".\n", - ctrl->subsys->subnqn); - module_put(ops->module); - up_read(&nvmf_transports_rwsem); - nvme_delete_ctrl_sync(ctrl); - return ERR_PTR(-EINVAL); - } - module_put(ops->module); up_read(&nvmf_transports_rwsem); return ctrl; diff --git a/drivers/nvme/host/fabrics.h b/drivers/nvme/host/fabrics.h index ef46c915b7b5..0cf0460a5c92 100644 --- a/drivers/nvme/host/fabrics.h +++ b/drivers/nvme/host/fabrics.h @@ -139,7 +139,9 @@ static inline bool nvmf_ctlr_matches_baseopts(struct nvme_ctrl *ctrl, struct nvmf_ctrl_options *opts) { - if (strcmp(opts->subsysnqn, ctrl->opts->subsysnqn) || + if (ctrl->state == NVME_CTRL_DELETING || + ctrl->state == NVME_CTRL_DEAD || + strcmp(opts->subsysnqn, ctrl->opts->subsysnqn) || strcmp(opts->host->nqn, ctrl->opts->host->nqn) || memcmp(&opts->host->id, &ctrl->opts->host->id, sizeof(uuid_t))) return false; diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c index 6cb26bcf6ec0..0bad65803271 100644 --- a/drivers/nvme/host/fc.c +++ b/drivers/nvme/host/fc.c @@ -1686,16 +1686,6 @@ done: goto check_error; } - /* - * Force failures of commands if we're killing the controller - * or have an error on a command used to create an new association - */ - if (status && - (blk_queue_dying(rq->q) || - ctrl->ctrl.state == NVME_CTRL_NEW || - ctrl->ctrl.state == NVME_CTRL_CONNECTING)) - status |= cpu_to_le16(NVME_SC_DNR << 1); - __nvme_fc_fcpop_chk_teardowns(ctrl, op, opstate); nvme_end_request(rq, status, result); @@ -2403,9 +2393,6 @@ nvme_fc_terminate_exchange(struct request *req, void *data, bool reserved) struct nvme_fc_ctrl *ctrl = to_fc_ctrl(nctrl); struct nvme_fc_fcp_op *op = blk_mq_rq_to_pdu(req); - if (!blk_mq_request_started(req)) - return; - __nvme_fc_abort_op(ctrl, op); } @@ -3284,6 +3271,8 @@ nvme_fc_create_ctrl(struct device *dev, struct nvmf_ctrl_options *opts) } spin_unlock_irqrestore(&nvme_fc_lock, flags); + pr_warn("%s: %s - %s combination not found\n", + __func__, opts->traddr, opts->host_traddr); return ERR_PTR(-ENOENT); } diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index 17d2f7cf3fed..de24fe77c80b 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h @@ -22,6 +22,7 @@ #include <linux/lightnvm.h> #include <linux/sed-opal.h> #include <linux/fault-inject.h> +#include <linux/rcupdate.h> extern unsigned int nvme_io_timeout; #define NVME_IO_TIMEOUT (nvme_io_timeout * HZ) @@ -180,6 +181,7 @@ struct nvme_ctrl { u16 kas; u8 npss; u8 apsta; + u32 oaes; u32 aen_result; unsigned int shutdown_timeout; unsigned int kato; @@ -192,6 +194,8 @@ struct nvme_ctrl { struct delayed_work ka_work; struct nvme_command ka_cmd; struct work_struct fw_act_work; +#define EVENT_NS_CHANGED (1 << 0) + unsigned long events; /* Power saving configuration */ u64 ps_max_latency_us; @@ -398,14 +402,13 @@ void nvme_stop_ctrl(struct nvme_ctrl *ctrl); void nvme_put_ctrl(struct nvme_ctrl *ctrl); int nvme_init_identify(struct nvme_ctrl *ctrl); -void nvme_queue_scan(struct nvme_ctrl *ctrl); void nvme_remove_namespaces(struct nvme_ctrl *ctrl); int nvme_sec_submit(void *data, u16 spsp, u8 secp, void *buffer, size_t len, bool send); void nvme_complete_async_event(struct nvme_ctrl *ctrl, __le16 status, - union nvme_result *res); + volatile union nvme_result *res); void nvme_stop_queues(struct nvme_ctrl *ctrl); void nvme_start_queues(struct nvme_ctrl *ctrl); @@ -454,7 +457,7 @@ static inline void nvme_mpath_clear_current_path(struct nvme_ns *ns) { struct nvme_ns_head *head = ns->head; - if (head && ns == srcu_dereference(head->current_path, &head->srcu)) + if (head && ns == rcu_access_pointer(head->current_path)) rcu_assign_pointer(head->current_path, NULL); } struct nvme_ns *nvme_find_path(struct nvme_ns_head *head); diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 17a0190bd88f..e526437bacbf 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -13,6 +13,7 @@ */ #include <linux/aer.h> +#include <linux/async.h> #include <linux/blkdev.h> #include <linux/blk-mq.h> #include <linux/blk-mq-pci.h> @@ -68,7 +69,6 @@ MODULE_PARM_DESC(io_queue_depth, "set io queue depth, should >= 2"); struct nvme_dev; struct nvme_queue; -static void nvme_process_cq(struct nvme_queue *nvmeq); static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown); /* @@ -147,9 +147,10 @@ static inline struct nvme_dev *to_nvme_dev(struct nvme_ctrl *ctrl) struct nvme_queue { struct device *q_dmadev; struct nvme_dev *dev; - spinlock_t q_lock; + spinlock_t sq_lock; struct nvme_command *sq_cmds; struct nvme_command __iomem *sq_cmds_io; + spinlock_t cq_lock ____cacheline_aligned_in_smp; volatile struct nvme_completion *cqes; struct blk_mq_tags **tags; dma_addr_t sq_dma_addr; @@ -159,9 +160,9 @@ struct nvme_queue { s16 cq_vector; u16 sq_tail; u16 cq_head; + u16 last_cq_head; u16 qid; u8 cq_phase; - u8 cqe_seen; u32 *dbbuf_sq_db; u32 *dbbuf_cq_db; u32 *dbbuf_sq_ei; @@ -420,28 +421,25 @@ static int nvme_pci_map_queues(struct blk_mq_tag_set *set) } /** - * __nvme_submit_cmd() - Copy a command into a queue and ring the doorbell + * nvme_submit_cmd() - Copy a command into a queue and ring the doorbell * @nvmeq: The queue to use * @cmd: The command to send - * - * Safe to use from interrupt context */ -static void __nvme_submit_cmd(struct nvme_queue *nvmeq, - struct nvme_command *cmd) +static void nvme_submit_cmd(struct nvme_queue *nvmeq, struct nvme_command *cmd) { - u16 tail = nvmeq->sq_tail; - + spin_lock(&nvmeq->sq_lock); if (nvmeq->sq_cmds_io) - memcpy_toio(&nvmeq->sq_cmds_io[tail], cmd, sizeof(*cmd)); + memcpy_toio(&nvmeq->sq_cmds_io[nvmeq->sq_tail], cmd, + sizeof(*cmd)); else - memcpy(&nvmeq->sq_cmds[tail], cmd, sizeof(*cmd)); + memcpy(&nvmeq->sq_cmds[nvmeq->sq_tail], cmd, sizeof(*cmd)); - if (++tail == nvmeq->q_depth) - tail = 0; - if (nvme_dbbuf_update_and_check_event(tail, nvmeq->dbbuf_sq_db, - nvmeq->dbbuf_sq_ei)) - writel(tail, nvmeq->q_db); - nvmeq->sq_tail = tail; + if (++nvmeq->sq_tail == nvmeq->q_depth) + nvmeq->sq_tail = 0; + if (nvme_dbbuf_update_and_check_event(nvmeq->sq_tail, + nvmeq->dbbuf_sq_db, nvmeq->dbbuf_sq_ei)) + writel(nvmeq->sq_tail, nvmeq->q_db); + spin_unlock(&nvmeq->sq_lock); } static void **nvme_pci_iod_list(struct request *req) @@ -872,6 +870,13 @@ static blk_status_t nvme_queue_rq(struct blk_mq_hw_ctx *hctx, struct nvme_command cmnd; blk_status_t ret; + /* + * We should not need to do this, but we're still using this to + * ensure we can drain requests on a dying queue. + */ + if (unlikely(nvmeq->cq_vector < 0)) + return BLK_STS_IOERR; + ret = nvme_setup_cmd(ns, req, &cmnd); if (ret) return ret; @@ -887,16 +892,7 @@ static blk_status_t nvme_queue_rq(struct blk_mq_hw_ctx *hctx, } blk_mq_start_request(req); - - spin_lock_irq(&nvmeq->q_lock); - if (unlikely(nvmeq->cq_vector < 0)) { - ret = BLK_STS_IOERR; - spin_unlock_irq(&nvmeq->q_lock); - goto out_cleanup_iod; - } - __nvme_submit_cmd(nvmeq, &cmnd); - nvme_process_cq(nvmeq); - spin_unlock_irq(&nvmeq->q_lock); + nvme_submit_cmd(nvmeq, &cmnd); return BLK_STS_OK; out_cleanup_iod: nvme_free_iod(dev, req); @@ -914,10 +910,10 @@ static void nvme_pci_complete_rq(struct request *req) } /* We read the CQE phase first to check if the rest of the entry is valid */ -static inline bool nvme_cqe_valid(struct nvme_queue *nvmeq, u16 head, - u16 phase) +static inline bool nvme_cqe_pending(struct nvme_queue *nvmeq) { - return (le16_to_cpu(nvmeq->cqes[head].status) & 1) == phase; + return (le16_to_cpu(nvmeq->cqes[nvmeq->cq_head].status) & 1) == + nvmeq->cq_phase; } static inline void nvme_ring_cq_doorbell(struct nvme_queue *nvmeq) @@ -931,9 +927,9 @@ static inline void nvme_ring_cq_doorbell(struct nvme_queue *nvmeq) } } -static inline void nvme_handle_cqe(struct nvme_queue *nvmeq, - struct nvme_completion *cqe) +static inline void nvme_handle_cqe(struct nvme_queue *nvmeq, u16 idx) { + volatile struct nvme_completion *cqe = &nvmeq->cqes[idx]; struct request *req; if (unlikely(cqe->command_id >= nvmeq->q_depth)) { @@ -956,83 +952,87 @@ static inline void nvme_handle_cqe(struct nvme_queue *nvmeq, return; } - nvmeq->cqe_seen = 1; req = blk_mq_tag_to_rq(*nvmeq->tags, cqe->command_id); nvme_end_request(req, cqe->status, cqe->result); } -static inline bool nvme_read_cqe(struct nvme_queue *nvmeq, - struct nvme_completion *cqe) +static void nvme_complete_cqes(struct nvme_queue *nvmeq, u16 start, u16 end) { - if (nvme_cqe_valid(nvmeq, nvmeq->cq_head, nvmeq->cq_phase)) { - *cqe = nvmeq->cqes[nvmeq->cq_head]; + while (start != end) { + nvme_handle_cqe(nvmeq, start); + if (++start == nvmeq->q_depth) + start = 0; + } +} - if (++nvmeq->cq_head == nvmeq->q_depth) { - nvmeq->cq_head = 0; - nvmeq->cq_phase = !nvmeq->cq_phase; - } - return true; +static inline void nvme_update_cq_head(struct nvme_queue *nvmeq) +{ + if (++nvmeq->cq_head == nvmeq->q_depth) { + nvmeq->cq_head = 0; + nvmeq->cq_phase = !nvmeq->cq_phase; } - return false; } -static void nvme_process_cq(struct nvme_queue *nvmeq) +static inline bool nvme_process_cq(struct nvme_queue *nvmeq, u16 *start, + u16 *end, int tag) { - struct nvme_completion cqe; - int consumed = 0; + bool found = false; - while (nvme_read_cqe(nvmeq, &cqe)) { - nvme_handle_cqe(nvmeq, &cqe); - consumed++; + *start = nvmeq->cq_head; + while (!found && nvme_cqe_pending(nvmeq)) { + if (nvmeq->cqes[nvmeq->cq_head].command_id == tag) + found = true; + nvme_update_cq_head(nvmeq); } + *end = nvmeq->cq_head; - if (consumed) + if (*start != *end) nvme_ring_cq_doorbell(nvmeq); + return found; } static irqreturn_t nvme_irq(int irq, void *data) { - irqreturn_t result; struct nvme_queue *nvmeq = data; - spin_lock(&nvmeq->q_lock); - nvme_process_cq(nvmeq); - result = nvmeq->cqe_seen ? IRQ_HANDLED : IRQ_NONE; - nvmeq->cqe_seen = 0; - spin_unlock(&nvmeq->q_lock); - return result; + irqreturn_t ret = IRQ_NONE; + u16 start, end; + + spin_lock(&nvmeq->cq_lock); + if (nvmeq->cq_head != nvmeq->last_cq_head) + ret = IRQ_HANDLED; + nvme_process_cq(nvmeq, &start, &end, -1); + nvmeq->last_cq_head = nvmeq->cq_head; + spin_unlock(&nvmeq->cq_lock); + + if (start != end) { + nvme_complete_cqes(nvmeq, start, end); + return IRQ_HANDLED; + } + + return ret; } static irqreturn_t nvme_irq_check(int irq, void *data) { struct nvme_queue *nvmeq = data; - if (nvme_cqe_valid(nvmeq, nvmeq->cq_head, nvmeq->cq_phase)) + if (nvme_cqe_pending(nvmeq)) return IRQ_WAKE_THREAD; return IRQ_NONE; } static int __nvme_poll(struct nvme_queue *nvmeq, unsigned int tag) { - struct nvme_completion cqe; - int found = 0, consumed = 0; + u16 start, end; + bool found; - if (!nvme_cqe_valid(nvmeq, nvmeq->cq_head, nvmeq->cq_phase)) + if (!nvme_cqe_pending(nvmeq)) return 0; - spin_lock_irq(&nvmeq->q_lock); - while (nvme_read_cqe(nvmeq, &cqe)) { - nvme_handle_cqe(nvmeq, &cqe); - consumed++; - - if (tag == cqe.command_id) { - found = 1; - break; - } - } - - if (consumed) - nvme_ring_cq_doorbell(nvmeq); - spin_unlock_irq(&nvmeq->q_lock); + spin_lock_irq(&nvmeq->cq_lock); + found = nvme_process_cq(nvmeq, &start, &end, tag); + spin_unlock_irq(&nvmeq->cq_lock); + nvme_complete_cqes(nvmeq, start, end); return found; } @@ -1052,10 +1052,7 @@ static void nvme_pci_submit_async_event(struct nvme_ctrl *ctrl) memset(&c, 0, sizeof(c)); c.common.opcode = nvme_admin_async_event; c.common.command_id = NVME_AQ_BLK_MQ_DEPTH; - - spin_lock_irq(&nvmeq->q_lock); - __nvme_submit_cmd(nvmeq, &c); - spin_unlock_irq(&nvmeq->q_lock); + nvme_submit_cmd(nvmeq, &c); } static int adapter_delete_queue(struct nvme_dev *dev, u8 opcode, u16 id) @@ -1070,7 +1067,7 @@ static int adapter_delete_queue(struct nvme_dev *dev, u8 opcode, u16 id) } static int adapter_alloc_cq(struct nvme_dev *dev, u16 qid, - struct nvme_queue *nvmeq) + struct nvme_queue *nvmeq, s16 vector) { struct nvme_command c; int flags = NVME_QUEUE_PHYS_CONTIG | NVME_CQ_IRQ_ENABLED; @@ -1085,7 +1082,7 @@ static int adapter_alloc_cq(struct nvme_dev *dev, u16 qid, c.create_cq.cqid = cpu_to_le16(qid); c.create_cq.qsize = cpu_to_le16(nvmeq->q_depth - 1); c.create_cq.cq_flags = cpu_to_le16(flags); - c.create_cq.irq_vector = cpu_to_le16(nvmeq->cq_vector); + c.create_cq.irq_vector = cpu_to_le16(vector); return nvme_submit_sync_cmd(dev->ctrl.admin_q, &c, NULL, 0); } @@ -1208,7 +1205,7 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req, bool reserved) nvme_warn_reset(dev, csts); nvme_dev_disable(dev, false); nvme_reset_ctrl(&dev->ctrl); - return BLK_EH_HANDLED; + return BLK_EH_DONE; } /* @@ -1218,24 +1215,24 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req, bool reserved) dev_warn(dev->ctrl.device, "I/O %d QID %d timeout, completion polled\n", req->tag, nvmeq->qid); - return BLK_EH_HANDLED; + return BLK_EH_DONE; } /* * Shutdown immediately if controller times out while starting. The * reset work will see the pci device disabled when it gets the forced * cancellation error. All outstanding requests are completed on - * shutdown, so we return BLK_EH_HANDLED. + * shutdown, so we return BLK_EH_DONE. */ switch (dev->ctrl.state) { case NVME_CTRL_CONNECTING: case NVME_CTRL_RESETTING: - dev_warn(dev->ctrl.device, + dev_warn_ratelimited(dev->ctrl.device, "I/O %d QID %d timeout, disable controller\n", req->tag, nvmeq->qid); nvme_dev_disable(dev, false); nvme_req(req)->flags |= NVME_REQ_CANCELLED; - return BLK_EH_HANDLED; + return BLK_EH_DONE; default: break; } @@ -1252,12 +1249,8 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req, bool reserved) nvme_dev_disable(dev, false); nvme_reset_ctrl(&dev->ctrl); - /* - * Mark the request as handled, since the inline shutdown - * forces all outstanding requests to complete. - */ nvme_req(req)->flags |= NVME_REQ_CANCELLED; - return BLK_EH_HANDLED; + return BLK_EH_DONE; } if (atomic_dec_return(&dev->ctrl.abort_limit) < 0) { @@ -1321,15 +1314,21 @@ static int nvme_suspend_queue(struct nvme_queue *nvmeq) { int vector; - spin_lock_irq(&nvmeq->q_lock); + spin_lock_irq(&nvmeq->cq_lock); if (nvmeq->cq_vector == -1) { - spin_unlock_irq(&nvmeq->q_lock); + spin_unlock_irq(&nvmeq->cq_lock); return 1; } vector = nvmeq->cq_vector; nvmeq->dev->online_queues--; nvmeq->cq_vector = -1; - spin_unlock_irq(&nvmeq->q_lock); + spin_unlock_irq(&nvmeq->cq_lock); + + /* + * Ensure that nvme_queue_rq() sees it ->cq_vector == -1 without + * having to grab the lock. + */ + mb(); if (!nvmeq->qid && nvmeq->dev->ctrl.admin_q) blk_mq_quiesce_queue(nvmeq->dev->ctrl.admin_q); @@ -1342,15 +1341,18 @@ static int nvme_suspend_queue(struct nvme_queue *nvmeq) static void nvme_disable_admin_queue(struct nvme_dev *dev, bool shutdown) { struct nvme_queue *nvmeq = &dev->queues[0]; + u16 start, end; if (shutdown) nvme_shutdown_ctrl(&dev->ctrl); else nvme_disable_ctrl(&dev->ctrl, dev->ctrl.cap); - spin_lock_irq(&nvmeq->q_lock); - nvme_process_cq(nvmeq); - spin_unlock_irq(&nvmeq->q_lock); + spin_lock_irq(&nvmeq->cq_lock); + nvme_process_cq(nvmeq, &start, &end, -1); + spin_unlock_irq(&nvmeq->cq_lock); + + nvme_complete_cqes(nvmeq, start, end); } static int nvme_cmb_qdepth(struct nvme_dev *dev, int nr_io_queues, @@ -1408,7 +1410,8 @@ static int nvme_alloc_queue(struct nvme_dev *dev, int qid, int depth) nvmeq->q_dmadev = dev->dev; nvmeq->dev = dev; - spin_lock_init(&nvmeq->q_lock); + spin_lock_init(&nvmeq->sq_lock); + spin_lock_init(&nvmeq->cq_lock); nvmeq->cq_head = 0; nvmeq->cq_phase = 1; nvmeq->q_db = &dev->dbs[qid * 2 * dev->db_stride]; @@ -1444,7 +1447,7 @@ static void nvme_init_queue(struct nvme_queue *nvmeq, u16 qid) { struct nvme_dev *dev = nvmeq->dev; - spin_lock_irq(&nvmeq->q_lock); + spin_lock_irq(&nvmeq->cq_lock); nvmeq->sq_tail = 0; nvmeq->cq_head = 0; nvmeq->cq_phase = 1; @@ -1452,13 +1455,14 @@ static void nvme_init_queue(struct nvme_queue *nvmeq, u16 qid) memset((void *)nvmeq->cqes, 0, CQ_SIZE(nvmeq->q_depth)); nvme_dbbuf_init(dev, nvmeq, qid); dev->online_queues++; - spin_unlock_irq(&nvmeq->q_lock); + spin_unlock_irq(&nvmeq->cq_lock); } static int nvme_create_queue(struct nvme_queue *nvmeq, int qid) { struct nvme_dev *dev = nvmeq->dev; int result; + s16 vector; if (dev->cmb && use_cmb_sqes && (dev->cmbsz & NVME_CMBSZ_SQS)) { unsigned offset = (qid - 1) * roundup(SQ_SIZE(nvmeq->q_depth), @@ -1471,15 +1475,21 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid) * A queue's vector matches the queue identifier unless the controller * has only one vector available. */ - nvmeq->cq_vector = dev->num_vecs == 1 ? 0 : qid; - result = adapter_alloc_cq(dev, qid, nvmeq); + vector = dev->num_vecs == 1 ? 0 : qid; + result = adapter_alloc_cq(dev, qid, nvmeq, vector); if (result < 0) - goto release_vector; + goto out; result = adapter_alloc_sq(dev, qid, nvmeq); if (result < 0) goto release_cq; + /* + * Set cq_vector after alloc cq/sq, otherwise nvme_suspend_queue will + * invoke free_irq for it and cause a 'Trying to free already-free IRQ + * xxx' warning if the create CQ/SQ command times out. + */ + nvmeq->cq_vector = vector; nvme_init_queue(nvmeq, qid); result = queue_request_irq(nvmeq); if (result < 0) @@ -1487,13 +1497,13 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid) return result; - release_sq: +release_sq: + nvmeq->cq_vector = -1; dev->online_queues--; adapter_delete_sq(dev, qid); - release_cq: +release_cq: adapter_delete_cq(dev, qid); - release_vector: - nvmeq->cq_vector = -1; +out: return result; } @@ -1997,19 +2007,22 @@ static void nvme_del_queue_end(struct request *req, blk_status_t error) static void nvme_del_cq_end(struct request *req, blk_status_t error) { struct nvme_queue *nvmeq = req->end_io_data; + u16 start, end; if (!error) { unsigned long flags; /* - * We might be called with the AQ q_lock held - * and the I/O queue q_lock should always + * We might be called with the AQ cq_lock held + * and the I/O queue cq_lock should always * nest inside the AQ one. */ - spin_lock_irqsave_nested(&nvmeq->q_lock, flags, + spin_lock_irqsave_nested(&nvmeq->cq_lock, flags, SINGLE_DEPTH_NESTING); - nvme_process_cq(nvmeq); - spin_unlock_irqrestore(&nvmeq->q_lock, flags); + nvme_process_cq(nvmeq, &start, &end, -1); + spin_unlock_irqrestore(&nvmeq->cq_lock, flags); + + nvme_complete_cqes(nvmeq, start, end); } nvme_del_queue_end(req, error); @@ -2497,6 +2510,15 @@ static unsigned long check_vendor_combination_bug(struct pci_dev *pdev) return 0; } +static void nvme_async_probe(void *data, async_cookie_t cookie) +{ + struct nvme_dev *dev = data; + + nvme_reset_ctrl_sync(&dev->ctrl); + flush_work(&dev->ctrl.scan_work); + nvme_put_ctrl(&dev->ctrl); +} + static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) { int node, result = -ENOMEM; @@ -2541,7 +2563,8 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) dev_info(dev->ctrl.device, "pci function %s\n", dev_name(&pdev->dev)); - nvme_reset_ctrl(&dev->ctrl); + nvme_get_ctrl(&dev->ctrl); + async_schedule(nvme_async_probe, dev); return 0; @@ -2685,6 +2708,9 @@ static pci_ers_result_t nvme_slot_reset(struct pci_dev *pdev) static void nvme_error_resume(struct pci_dev *pdev) { + struct nvme_dev *dev = pci_get_drvdata(pdev); + + flush_work(&dev->ctrl.reset_work); pci_cleanup_aer_uncorrect_error_status(pdev); } @@ -2714,6 +2740,8 @@ static const struct pci_device_id nvme_id_table[] = { NVME_QUIRK_MEDIUM_PRIO_SQ }, { PCI_VDEVICE(INTEL, 0x5845), /* Qemu emulated controller */ .driver_data = NVME_QUIRK_IDENTIFY_CNS, }, + { PCI_DEVICE(0x1bb1, 0x0100), /* Seagate Nytro Flash Storage */ + .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, { PCI_DEVICE(0x1c58, 0x0003), /* HGST adapter */ .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, { PCI_DEVICE(0x1c58, 0x0023), /* WDC SN200 adapter */ @@ -2728,6 +2756,8 @@ static const struct pci_device_id nvme_id_table[] = { .driver_data = NVME_QUIRK_LIGHTNVM, }, { PCI_DEVICE(0x1d1d, 0x2807), /* CNEX WL */ .driver_data = NVME_QUIRK_LIGHTNVM, }, + { PCI_DEVICE(0x1d1d, 0x2601), /* CNEX Granby */ + .driver_data = NVME_QUIRK_LIGHTNVM, }, { PCI_DEVICE_CLASS(PCI_CLASS_STORAGE_EXPRESS, 0xffffff) }, { PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2001) }, { PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2003) }, diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c index 1eb4438a8763..7b3f08410430 100644 --- a/drivers/nvme/host/rdma.c +++ b/drivers/nvme/host/rdma.c @@ -778,7 +778,7 @@ static int nvme_rdma_configure_admin_queue(struct nvme_rdma_ctrl *ctrl, if (error) { dev_err(ctrl->ctrl.device, "prop_get NVME_REG_CAP failed\n"); - goto out_cleanup_queue; + goto out_stop_queue; } ctrl->ctrl.sqsize = @@ -786,23 +786,25 @@ static int nvme_rdma_configure_admin_queue(struct nvme_rdma_ctrl *ctrl, error = nvme_enable_ctrl(&ctrl->ctrl, ctrl->ctrl.cap); if (error) - goto out_cleanup_queue; + goto out_stop_queue; ctrl->ctrl.max_hw_sectors = (ctrl->max_fr_pages - 1) << (ilog2(SZ_4K) - 9); error = nvme_init_identify(&ctrl->ctrl); if (error) - goto out_cleanup_queue; + goto out_stop_queue; error = nvme_rdma_alloc_qe(ctrl->queues[0].device->dev, &ctrl->async_event_sqe, sizeof(struct nvme_command), DMA_TO_DEVICE); if (error) - goto out_cleanup_queue; + goto out_stop_queue; return 0; +out_stop_queue: + nvme_rdma_stop_queue(&ctrl->queues[0]); out_cleanup_queue: if (new) blk_cleanup_queue(ctrl->ctrl.admin_q); @@ -1598,7 +1600,7 @@ nvme_rdma_timeout(struct request *rq, bool reserved) /* fail with DNR on cmd timeout */ nvme_req(rq)->status = NVME_SC_ABORT_REQ | NVME_SC_DNR; - return BLK_EH_HANDLED; + return BLK_EH_DONE; } static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx, diff --git a/drivers/nvme/host/trace.h b/drivers/nvme/host/trace.h index ea91fccd1bc0..01390f0e1671 100644 --- a/drivers/nvme/host/trace.h +++ b/drivers/nvme/host/trace.h @@ -148,8 +148,8 @@ TRACE_EVENT(nvme_complete_rq, __entry->flags = nvme_req(req)->flags; __entry->status = nvme_req(req)->status; ), - TP_printk("cmdid=%u, qid=%d, res=%llu, retries=%u, flags=0x%x, status=%u", - __entry->cid, __entry->qid, __entry->result, + TP_printk("qid=%d, cmdid=%u, res=%llu, retries=%u, flags=0x%x, status=%u", + __entry->qid, __entry->cid, __entry->result, __entry->retries, __entry->flags, __entry->status) ); diff --git a/drivers/nvme/target/Makefile b/drivers/nvme/target/Makefile index 488250189c99..8118c93391c6 100644 --- a/drivers/nvme/target/Makefile +++ b/drivers/nvme/target/Makefile @@ -6,8 +6,8 @@ obj-$(CONFIG_NVME_TARGET_RDMA) += nvmet-rdma.o obj-$(CONFIG_NVME_TARGET_FC) += nvmet-fc.o obj-$(CONFIG_NVME_TARGET_FCLOOP) += nvme-fcloop.o -nvmet-y += core.o configfs.o admin-cmd.o io-cmd.o fabrics-cmd.o \ - discovery.o +nvmet-y += core.o configfs.o admin-cmd.o fabrics-cmd.o \ + discovery.o io-cmd-file.o io-cmd-bdev.o nvme-loop-y += loop.o nvmet-rdma-y += rdma.o nvmet-fc-y += fc.o diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c index 5e0e9fcc0d4d..ead8fbe6922e 100644 --- a/drivers/nvme/target/admin-cmd.c +++ b/drivers/nvme/target/admin-cmd.c @@ -32,6 +32,11 @@ u32 nvmet_get_log_page_len(struct nvme_command *cmd) return len; } +static void nvmet_execute_get_log_page_noop(struct nvmet_req *req) +{ + nvmet_req_complete(req, nvmet_zero_sgl(req, 0, req->data_len)); +} + static u16 nvmet_get_smart_log_nsid(struct nvmet_req *req, struct nvme_smart_log *slog) { @@ -45,6 +50,10 @@ static u16 nvmet_get_smart_log_nsid(struct nvmet_req *req, return NVME_SC_INVALID_NS; } + /* we don't have the right data for file backed ns */ + if (!ns->bdev) + goto out; + host_reads = part_stat_read(ns->bdev->bd_part, ios[READ]); data_units_read = part_stat_read(ns->bdev->bd_part, sectors[READ]); host_writes = part_stat_read(ns->bdev->bd_part, ios[WRITE]); @@ -54,6 +63,7 @@ static u16 nvmet_get_smart_log_nsid(struct nvmet_req *req, put_unaligned_le64(data_units_read, &slog->data_units_read[0]); put_unaligned_le64(host_writes, &slog->host_writes[0]); put_unaligned_le64(data_units_written, &slog->data_units_written[0]); +out: nvmet_put_namespace(ns); return NVME_SC_SUCCESS; @@ -71,6 +81,9 @@ static u16 nvmet_get_smart_log_all(struct nvmet_req *req, rcu_read_lock(); list_for_each_entry_rcu(ns, &ctrl->subsys->namespaces, dev_link) { + /* we don't have the right data for file backed ns */ + if (!ns->bdev) + continue; host_reads += part_stat_read(ns->bdev->bd_part, ios[READ]); data_units_read += part_stat_read(ns->bdev->bd_part, sectors[READ]); @@ -89,74 +102,50 @@ static u16 nvmet_get_smart_log_all(struct nvmet_req *req, return NVME_SC_SUCCESS; } -static u16 nvmet_get_smart_log(struct nvmet_req *req, - struct nvme_smart_log *slog) +static void nvmet_execute_get_log_page_smart(struct nvmet_req *req) { - u16 status; + struct nvme_smart_log *log; + u16 status = NVME_SC_INTERNAL; + + if (req->data_len != sizeof(*log)) + goto out; + + log = kzalloc(sizeof(*log), GFP_KERNEL); + if (!log) + goto out; - WARN_ON(req == NULL || slog == NULL); if (req->cmd->get_log_page.nsid == cpu_to_le32(NVME_NSID_ALL)) - status = nvmet_get_smart_log_all(req, slog); + status = nvmet_get_smart_log_all(req, log); else - status = nvmet_get_smart_log_nsid(req, slog); - return status; + status = nvmet_get_smart_log_nsid(req, log); + if (status) + goto out; + + status = nvmet_copy_to_sgl(req, 0, log, sizeof(*log)); +out: + nvmet_req_complete(req, status); } -static void nvmet_execute_get_log_page(struct nvmet_req *req) +static void nvmet_execute_get_log_changed_ns(struct nvmet_req *req) { - struct nvme_smart_log *smart_log; - size_t data_len = nvmet_get_log_page_len(req->cmd); - void *buf; - u16 status = 0; + struct nvmet_ctrl *ctrl = req->sq->ctrl; + u16 status = NVME_SC_INTERNAL; + size_t len; - buf = kzalloc(data_len, GFP_KERNEL); - if (!buf) { - status = NVME_SC_INTERNAL; + if (req->data_len != NVME_MAX_CHANGED_NAMESPACES * sizeof(__le32)) goto out; - } - switch (req->cmd->get_log_page.lid) { - case NVME_LOG_ERROR: - /* - * We currently never set the More bit in the status field, - * so all error log entries are invalid and can be zeroed out. - * This is called a minum viable implementation (TM) of this - * mandatory log page. - */ - break; - case NVME_LOG_SMART: - /* - * XXX: fill out actual smart log - * - * We might have a hard time coming up with useful values for - * many of the fields, and even when we have useful data - * available (e.g. units or commands read/written) those aren't - * persistent over power loss. - */ - if (data_len != sizeof(*smart_log)) { - status = NVME_SC_INTERNAL; - goto err; - } - smart_log = buf; - status = nvmet_get_smart_log(req, smart_log); - if (status) - goto err; - break; - case NVME_LOG_FW_SLOT: - /* - * We only support a single firmware slot which always is - * active, so we can zero out the whole firmware slot log and - * still claim to fully implement this mandatory log page. - */ - break; - default: - BUG(); - } - - status = nvmet_copy_to_sgl(req, 0, buf, data_len); - -err: - kfree(buf); + mutex_lock(&ctrl->lock); + if (ctrl->nr_changed_ns == U32_MAX) + len = sizeof(__le32); + else + len = ctrl->nr_changed_ns * sizeof(__le32); + status = nvmet_copy_to_sgl(req, 0, ctrl->changed_ns_list, len); + if (!status) + status = nvmet_zero_sgl(req, len, req->data_len - len); + ctrl->nr_changed_ns = 0; + clear_bit(NVME_AEN_CFG_NS_ATTR, &ctrl->aen_masked); + mutex_unlock(&ctrl->lock); out: nvmet_req_complete(req, status); } @@ -201,7 +190,7 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req) id->ver = cpu_to_le32(ctrl->subsys->ver); /* XXX: figure out what to do about RTD3R/RTD3 */ - id->oaes = cpu_to_le32(1 << 8); + id->oaes = cpu_to_le32(NVMET_AEN_CFG_OPTIONAL); id->ctratt = cpu_to_le32(1 << 0); id->oacs = 0; @@ -447,6 +436,16 @@ static void nvmet_execute_set_features(struct nvmet_req *req) req->sq->ctrl->kato = DIV_ROUND_UP(val32, 1000); nvmet_set_result(req, req->sq->ctrl->kato); break; + case NVME_FEAT_ASYNC_EVENT: + val32 = le32_to_cpu(req->cmd->common.cdw10[1]); + if (val32 & ~NVMET_AEN_CFG_ALL) { + status = NVME_SC_INVALID_FIELD | NVME_SC_DNR; + break; + } + + WRITE_ONCE(req->sq->ctrl->aen_enabled, val32); + nvmet_set_result(req, val32); + break; case NVME_FEAT_HOST_ID: status = NVME_SC_CMD_SEQ_ERROR | NVME_SC_DNR; break; @@ -485,9 +484,10 @@ static void nvmet_execute_get_features(struct nvmet_req *req) break; case NVME_FEAT_WRITE_ATOMIC: break; +#endif case NVME_FEAT_ASYNC_EVENT: + nvmet_set_result(req, READ_ONCE(req->sq->ctrl->aen_enabled)); break; -#endif case NVME_FEAT_VOLATILE_WC: nvmet_set_result(req, 1); break; @@ -548,8 +548,6 @@ u16 nvmet_parse_admin_cmd(struct nvmet_req *req) struct nvme_command *cmd = req->cmd; u16 ret; - req->ns = NULL; - ret = nvmet_check_ctrl_status(req, cmd); if (unlikely(ret)) return ret; @@ -560,9 +558,28 @@ u16 nvmet_parse_admin_cmd(struct nvmet_req *req) switch (cmd->get_log_page.lid) { case NVME_LOG_ERROR: + /* + * We currently never set the More bit in the status + * field, so all error log entries are invalid and can + * be zeroed out. This is called a minum viable + * implementation (TM) of this mandatory log page. + */ + req->execute = nvmet_execute_get_log_page_noop; + return 0; case NVME_LOG_SMART: + req->execute = nvmet_execute_get_log_page_smart; + return 0; case NVME_LOG_FW_SLOT: - req->execute = nvmet_execute_get_log_page; + /* + * We only support a single firmware slot which always + * is active, so we can zero out the whole firmware slot + * log and still claim to fully implement this mandatory + * log page. + */ + req->execute = nvmet_execute_get_log_page_noop; + return 0; + case NVME_LOG_CHANGED_NS: + req->execute = nvmet_execute_get_log_changed_ns; return 0; } break; diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c index e95424f172fd..a03da764ecae 100644 --- a/drivers/nvme/target/core.c +++ b/drivers/nvme/target/core.c @@ -57,6 +57,13 @@ u16 nvmet_copy_from_sgl(struct nvmet_req *req, off_t off, void *buf, size_t len) return 0; } +u16 nvmet_zero_sgl(struct nvmet_req *req, off_t off, size_t len) +{ + if (sg_zero_buffer(req->sg, req->sg_cnt, len, off) != len) + return NVME_SC_SGL_INVALID_DATA | NVME_SC_DNR; + return 0; +} + static unsigned int nvmet_max_nsid(struct nvmet_subsys *subsys) { struct nvmet_ns *ns; @@ -137,6 +144,51 @@ static void nvmet_add_async_event(struct nvmet_ctrl *ctrl, u8 event_type, schedule_work(&ctrl->async_event_work); } +static bool nvmet_aen_disabled(struct nvmet_ctrl *ctrl, u32 aen) +{ + if (!(READ_ONCE(ctrl->aen_enabled) & aen)) + return true; + return test_and_set_bit(aen, &ctrl->aen_masked); +} + +static void nvmet_add_to_changed_ns_log(struct nvmet_ctrl *ctrl, __le32 nsid) +{ + u32 i; + + mutex_lock(&ctrl->lock); + if (ctrl->nr_changed_ns > NVME_MAX_CHANGED_NAMESPACES) + goto out_unlock; + + for (i = 0; i < ctrl->nr_changed_ns; i++) { + if (ctrl->changed_ns_list[i] == nsid) + goto out_unlock; + } + + if (ctrl->nr_changed_ns == NVME_MAX_CHANGED_NAMESPACES) { + ctrl->changed_ns_list[0] = cpu_to_le32(0xffffffff); + ctrl->nr_changed_ns = U32_MAX; + goto out_unlock; + } + + ctrl->changed_ns_list[ctrl->nr_changed_ns++] = nsid; +out_unlock: + mutex_unlock(&ctrl->lock); +} + +static void nvmet_ns_changed(struct nvmet_subsys *subsys, u32 nsid) +{ + struct nvmet_ctrl *ctrl; + + list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry) { + nvmet_add_to_changed_ns_log(ctrl, cpu_to_le32(nsid)); + if (nvmet_aen_disabled(ctrl, NVME_AEN_CFG_NS_ATTR)) + continue; + nvmet_add_async_event(ctrl, NVME_AER_TYPE_NOTICE, + NVME_AER_NOTICE_NS_CHANGED, + NVME_LOG_CHANGED_NS); + } +} + int nvmet_register_transport(const struct nvmet_fabrics_ops *ops) { int ret = 0; @@ -271,33 +323,31 @@ void nvmet_put_namespace(struct nvmet_ns *ns) percpu_ref_put(&ns->ref); } +static void nvmet_ns_dev_disable(struct nvmet_ns *ns) +{ + nvmet_bdev_ns_disable(ns); + nvmet_file_ns_disable(ns); +} + int nvmet_ns_enable(struct nvmet_ns *ns) { struct nvmet_subsys *subsys = ns->subsys; - struct nvmet_ctrl *ctrl; int ret = 0; mutex_lock(&subsys->lock); if (ns->enabled) goto out_unlock; - ns->bdev = blkdev_get_by_path(ns->device_path, FMODE_READ | FMODE_WRITE, - NULL); - if (IS_ERR(ns->bdev)) { - pr_err("failed to open block device %s: (%ld)\n", - ns->device_path, PTR_ERR(ns->bdev)); - ret = PTR_ERR(ns->bdev); - ns->bdev = NULL; + ret = nvmet_bdev_ns_enable(ns); + if (ret) + ret = nvmet_file_ns_enable(ns); + if (ret) goto out_unlock; - } - - ns->size = i_size_read(ns->bdev->bd_inode); - ns->blksize_shift = blksize_bits(bdev_logical_block_size(ns->bdev)); ret = percpu_ref_init(&ns->ref, nvmet_destroy_namespace, 0, GFP_KERNEL); if (ret) - goto out_blkdev_put; + goto out_dev_put; if (ns->nsid > subsys->max_nsid) subsys->max_nsid = ns->nsid; @@ -320,24 +370,20 @@ int nvmet_ns_enable(struct nvmet_ns *ns) list_add_tail_rcu(&ns->dev_link, &old->dev_link); } - list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry) - nvmet_add_async_event(ctrl, NVME_AER_TYPE_NOTICE, 0, 0); - + nvmet_ns_changed(subsys, ns->nsid); ns->enabled = true; ret = 0; out_unlock: mutex_unlock(&subsys->lock); return ret; -out_blkdev_put: - blkdev_put(ns->bdev, FMODE_WRITE|FMODE_READ); - ns->bdev = NULL; +out_dev_put: + nvmet_ns_dev_disable(ns); goto out_unlock; } void nvmet_ns_disable(struct nvmet_ns *ns) { struct nvmet_subsys *subsys = ns->subsys; - struct nvmet_ctrl *ctrl; mutex_lock(&subsys->lock); if (!ns->enabled) @@ -363,11 +409,8 @@ void nvmet_ns_disable(struct nvmet_ns *ns) percpu_ref_exit(&ns->ref); mutex_lock(&subsys->lock); - list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry) - nvmet_add_async_event(ctrl, NVME_AER_TYPE_NOTICE, 0, 0); - - if (ns->bdev) - blkdev_put(ns->bdev, FMODE_WRITE|FMODE_READ); + nvmet_ns_changed(subsys, ns->nsid); + nvmet_ns_dev_disable(ns); out_unlock: mutex_unlock(&subsys->lock); } @@ -499,6 +542,25 @@ int nvmet_sq_init(struct nvmet_sq *sq) } EXPORT_SYMBOL_GPL(nvmet_sq_init); +static u16 nvmet_parse_io_cmd(struct nvmet_req *req) +{ + struct nvme_command *cmd = req->cmd; + u16 ret; + + ret = nvmet_check_ctrl_status(req, cmd); + if (unlikely(ret)) + return ret; + + req->ns = nvmet_find_namespace(req->sq->ctrl, cmd->rw.nsid); + if (unlikely(!req->ns)) + return NVME_SC_INVALID_NS | NVME_SC_DNR; + + if (req->ns->file) + return nvmet_file_parse_io_cmd(req); + else + return nvmet_bdev_parse_io_cmd(req); +} + bool nvmet_req_init(struct nvmet_req *req, struct nvmet_cq *cq, struct nvmet_sq *sq, const struct nvmet_fabrics_ops *ops) { @@ -710,15 +772,14 @@ out: u16 nvmet_check_ctrl_status(struct nvmet_req *req, struct nvme_command *cmd) { if (unlikely(!(req->sq->ctrl->cc & NVME_CC_ENABLE))) { - pr_err("got io cmd %d while CC.EN == 0 on qid = %d\n", + pr_err("got cmd %d while CC.EN == 0 on qid = %d\n", cmd->common.opcode, req->sq->qid); return NVME_SC_CMD_SEQ_ERROR | NVME_SC_DNR; } if (unlikely(!(req->sq->ctrl->csts & NVME_CSTS_RDY))) { - pr_err("got io cmd %d while CSTS.RDY == 0 on qid = %d\n", + pr_err("got cmd %d while CSTS.RDY == 0 on qid = %d\n", cmd->common.opcode, req->sq->qid); - req->ns = NULL; return NVME_SC_CMD_SEQ_ERROR | NVME_SC_DNR; } return 0; @@ -809,12 +870,18 @@ u16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn, kref_init(&ctrl->ref); ctrl->subsys = subsys; + WRITE_ONCE(ctrl->aen_enabled, NVMET_AEN_CFG_OPTIONAL); + + ctrl->changed_ns_list = kmalloc_array(NVME_MAX_CHANGED_NAMESPACES, + sizeof(__le32), GFP_KERNEL); + if (!ctrl->changed_ns_list) + goto out_free_ctrl; ctrl->cqs = kcalloc(subsys->max_qid + 1, sizeof(struct nvmet_cq *), GFP_KERNEL); if (!ctrl->cqs) - goto out_free_ctrl; + goto out_free_changed_ns_list; ctrl->sqs = kcalloc(subsys->max_qid + 1, sizeof(struct nvmet_sq *), @@ -872,6 +939,8 @@ out_free_sqs: kfree(ctrl->sqs); out_free_cqs: kfree(ctrl->cqs); +out_free_changed_ns_list: + kfree(ctrl->changed_ns_list); out_free_ctrl: kfree(ctrl); out_put_subsystem: @@ -898,6 +967,7 @@ static void nvmet_ctrl_free(struct kref *ref) kfree(ctrl->sqs); kfree(ctrl->cqs); + kfree(ctrl->changed_ns_list); kfree(ctrl); nvmet_subsys_put(subsys); diff --git a/drivers/nvme/target/discovery.c b/drivers/nvme/target/discovery.c index 231e04e0a496..08656b849bd6 100644 --- a/drivers/nvme/target/discovery.c +++ b/drivers/nvme/target/discovery.c @@ -187,8 +187,6 @@ u16 nvmet_parse_discovery_cmd(struct nvmet_req *req) { struct nvme_command *cmd = req->cmd; - req->ns = NULL; - if (unlikely(!(req->sq->ctrl->csts & NVME_CSTS_RDY))) { pr_err("got cmd %d while not ready\n", cmd->common.opcode); diff --git a/drivers/nvme/target/fabrics-cmd.c b/drivers/nvme/target/fabrics-cmd.c index 19e9e42ae943..d84ae004cb85 100644 --- a/drivers/nvme/target/fabrics-cmd.c +++ b/drivers/nvme/target/fabrics-cmd.c @@ -77,8 +77,6 @@ u16 nvmet_parse_fabrics_cmd(struct nvmet_req *req) { struct nvme_command *cmd = req->cmd; - req->ns = NULL; - switch (cmd->fabrics.fctype) { case nvme_fabrics_type_property_set: req->data_len = 0; @@ -242,8 +240,6 @@ u16 nvmet_parse_connect_cmd(struct nvmet_req *req) { struct nvme_command *cmd = req->cmd; - req->ns = NULL; - if (cmd->common.opcode != nvme_fabrics_command) { pr_err("invalid command 0x%x on unconnected queue.\n", cmd->fabrics.opcode); diff --git a/drivers/nvme/target/fc.c b/drivers/nvme/target/fc.c index 33ee8d3145f8..408279cb6f2c 100644 --- a/drivers/nvme/target/fc.c +++ b/drivers/nvme/target/fc.c @@ -31,7 +31,7 @@ /* *************************** Data Structures/Defines ****************** */ -#define NVMET_LS_CTX_COUNT 4 +#define NVMET_LS_CTX_COUNT 256 /* for this implementation, assume small single frame rqst/rsp */ #define NVME_FC_MAX_LS_BUFFER_SIZE 2048 diff --git a/drivers/nvme/target/io-cmd.c b/drivers/nvme/target/io-cmd-bdev.c index cd2344179673..e0b0f7df70c2 100644 --- a/drivers/nvme/target/io-cmd.c +++ b/drivers/nvme/target/io-cmd-bdev.c @@ -16,6 +16,34 @@ #include <linux/module.h> #include "nvmet.h" +int nvmet_bdev_ns_enable(struct nvmet_ns *ns) +{ + int ret; + + ns->bdev = blkdev_get_by_path(ns->device_path, + FMODE_READ | FMODE_WRITE, NULL); + if (IS_ERR(ns->bdev)) { + ret = PTR_ERR(ns->bdev); + if (ret != -ENOTBLK) { + pr_err("failed to open block device %s: (%ld)\n", + ns->device_path, PTR_ERR(ns->bdev)); + } + ns->bdev = NULL; + return ret; + } + ns->size = i_size_read(ns->bdev->bd_inode); + ns->blksize_shift = blksize_bits(bdev_logical_block_size(ns->bdev)); + return 0; +} + +void nvmet_bdev_ns_disable(struct nvmet_ns *ns) +{ + if (ns->bdev) { + blkdev_put(ns->bdev, FMODE_WRITE | FMODE_READ); + ns->bdev = NULL; + } +} + static void nvmet_bio_done(struct bio *bio) { struct nvmet_req *req = bio->bi_private; @@ -23,20 +51,14 @@ static void nvmet_bio_done(struct bio *bio) nvmet_req_complete(req, bio->bi_status ? NVME_SC_INTERNAL | NVME_SC_DNR : 0); - if (bio != &req->inline_bio) + if (bio != &req->b.inline_bio) bio_put(bio); } -static inline u32 nvmet_rw_len(struct nvmet_req *req) -{ - return ((u32)le16_to_cpu(req->cmd->rw.length) + 1) << - req->ns->blksize_shift; -} - -static void nvmet_execute_rw(struct nvmet_req *req) +static void nvmet_bdev_execute_rw(struct nvmet_req *req) { int sg_cnt = req->sg_cnt; - struct bio *bio = &req->inline_bio; + struct bio *bio = &req->b.inline_bio; struct scatterlist *sg; sector_t sector; blk_qc_t cookie; @@ -89,9 +111,9 @@ static void nvmet_execute_rw(struct nvmet_req *req) blk_poll(bdev_get_queue(req->ns->bdev), cookie); } -static void nvmet_execute_flush(struct nvmet_req *req) +static void nvmet_bdev_execute_flush(struct nvmet_req *req) { - struct bio *bio = &req->inline_bio; + struct bio *bio = &req->b.inline_bio; bio_init(bio, req->inline_bvec, ARRAY_SIZE(req->inline_bvec)); bio_set_dev(bio, req->ns->bdev); @@ -102,7 +124,7 @@ static void nvmet_execute_flush(struct nvmet_req *req) submit_bio(bio); } -static u16 nvmet_discard_range(struct nvmet_ns *ns, +static u16 nvmet_bdev_discard_range(struct nvmet_ns *ns, struct nvme_dsm_range *range, struct bio **bio) { int ret; @@ -116,7 +138,7 @@ static u16 nvmet_discard_range(struct nvmet_ns *ns, return 0; } -static void nvmet_execute_discard(struct nvmet_req *req) +static void nvmet_bdev_execute_discard(struct nvmet_req *req) { struct nvme_dsm_range range; struct bio *bio = NULL; @@ -129,7 +151,7 @@ static void nvmet_execute_discard(struct nvmet_req *req) if (status) break; - status = nvmet_discard_range(req->ns, &range, &bio); + status = nvmet_bdev_discard_range(req->ns, &range, &bio); if (status) break; } @@ -148,11 +170,11 @@ static void nvmet_execute_discard(struct nvmet_req *req) } } -static void nvmet_execute_dsm(struct nvmet_req *req) +static void nvmet_bdev_execute_dsm(struct nvmet_req *req) { switch (le32_to_cpu(req->cmd->dsm.attributes)) { case NVME_DSMGMT_AD: - nvmet_execute_discard(req); + nvmet_bdev_execute_discard(req); return; case NVME_DSMGMT_IDR: case NVME_DSMGMT_IDW: @@ -163,7 +185,7 @@ static void nvmet_execute_dsm(struct nvmet_req *req) } } -static void nvmet_execute_write_zeroes(struct nvmet_req *req) +static void nvmet_bdev_execute_write_zeroes(struct nvmet_req *req) { struct nvme_write_zeroes_cmd *write_zeroes = &req->cmd->write_zeroes; struct bio *bio = NULL; @@ -189,38 +211,27 @@ static void nvmet_execute_write_zeroes(struct nvmet_req *req) } } -u16 nvmet_parse_io_cmd(struct nvmet_req *req) +u16 nvmet_bdev_parse_io_cmd(struct nvmet_req *req) { struct nvme_command *cmd = req->cmd; - u16 ret; - - ret = nvmet_check_ctrl_status(req, cmd); - if (unlikely(ret)) { - req->ns = NULL; - return ret; - } - - req->ns = nvmet_find_namespace(req->sq->ctrl, cmd->rw.nsid); - if (unlikely(!req->ns)) - return NVME_SC_INVALID_NS | NVME_SC_DNR; switch (cmd->common.opcode) { case nvme_cmd_read: case nvme_cmd_write: - req->execute = nvmet_execute_rw; + req->execute = nvmet_bdev_execute_rw; req->data_len = nvmet_rw_len(req); return 0; case nvme_cmd_flush: - req->execute = nvmet_execute_flush; + req->execute = nvmet_bdev_execute_flush; req->data_len = 0; return 0; case nvme_cmd_dsm: - req->execute = nvmet_execute_dsm; + req->execute = nvmet_bdev_execute_dsm; req->data_len = (le32_to_cpu(cmd->dsm.nr) + 1) * sizeof(struct nvme_dsm_range); return 0; case nvme_cmd_write_zeroes: - req->execute = nvmet_execute_write_zeroes; + req->execute = nvmet_bdev_execute_write_zeroes; return 0; default: pr_err("unhandled cmd %d on qid %d\n", cmd->common.opcode, diff --git a/drivers/nvme/target/io-cmd-file.c b/drivers/nvme/target/io-cmd-file.c new file mode 100644 index 000000000000..8c42b3a8c420 --- /dev/null +++ b/drivers/nvme/target/io-cmd-file.c @@ -0,0 +1,304 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * NVMe Over Fabrics Target File I/O commands implementation. + * Copyright (c) 2017-2018 Western Digital Corporation or its + * affiliates. + */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/uio.h> +#include <linux/falloc.h> +#include <linux/file.h> +#include "nvmet.h" + +#define NVMET_MAX_MPOOL_BVEC 16 +#define NVMET_MIN_MPOOL_OBJ 16 + +void nvmet_file_ns_disable(struct nvmet_ns *ns) +{ + if (ns->file) { + mempool_destroy(ns->bvec_pool); + ns->bvec_pool = NULL; + kmem_cache_destroy(ns->bvec_cache); + ns->bvec_cache = NULL; + fput(ns->file); + ns->file = NULL; + } +} + +int nvmet_file_ns_enable(struct nvmet_ns *ns) +{ + int ret; + struct kstat stat; + + ns->file = filp_open(ns->device_path, + O_RDWR | O_LARGEFILE | O_DIRECT, 0); + if (IS_ERR(ns->file)) { + pr_err("failed to open file %s: (%ld)\n", + ns->device_path, PTR_ERR(ns->file)); + return PTR_ERR(ns->file); + } + + ret = vfs_getattr(&ns->file->f_path, + &stat, STATX_SIZE, AT_STATX_FORCE_SYNC); + if (ret) + goto err; + + ns->size = stat.size; + ns->blksize_shift = file_inode(ns->file)->i_blkbits; + + ns->bvec_cache = kmem_cache_create("nvmet-bvec", + NVMET_MAX_MPOOL_BVEC * sizeof(struct bio_vec), + 0, SLAB_HWCACHE_ALIGN, NULL); + if (!ns->bvec_cache) { + ret = -ENOMEM; + goto err; + } + + ns->bvec_pool = mempool_create(NVMET_MIN_MPOOL_OBJ, mempool_alloc_slab, + mempool_free_slab, ns->bvec_cache); + + if (!ns->bvec_pool) { + ret = -ENOMEM; + goto err; + } + + return ret; +err: + ns->size = 0; + ns->blksize_shift = 0; + nvmet_file_ns_disable(ns); + return ret; +} + +static void nvmet_file_init_bvec(struct bio_vec *bv, struct sg_page_iter *iter) +{ + bv->bv_page = sg_page_iter_page(iter); + bv->bv_offset = iter->sg->offset; + bv->bv_len = PAGE_SIZE - iter->sg->offset; +} + +static ssize_t nvmet_file_submit_bvec(struct nvmet_req *req, loff_t pos, + unsigned long nr_segs, size_t count) +{ + struct kiocb *iocb = &req->f.iocb; + ssize_t (*call_iter)(struct kiocb *iocb, struct iov_iter *iter); + struct iov_iter iter; + int ki_flags = 0, rw; + ssize_t ret; + + if (req->cmd->rw.opcode == nvme_cmd_write) { + if (req->cmd->rw.control & cpu_to_le16(NVME_RW_FUA)) + ki_flags = IOCB_DSYNC; + call_iter = req->ns->file->f_op->write_iter; + rw = WRITE; + } else { + call_iter = req->ns->file->f_op->read_iter; + rw = READ; + } + + iov_iter_bvec(&iter, ITER_BVEC | rw, req->f.bvec, nr_segs, count); + + iocb->ki_pos = pos; + iocb->ki_filp = req->ns->file; + iocb->ki_flags = IOCB_DIRECT | ki_flags; + + ret = call_iter(iocb, &iter); + + if (ret != -EIOCBQUEUED && iocb->ki_complete) + iocb->ki_complete(iocb, ret, 0); + + return ret; +} + +static void nvmet_file_io_done(struct kiocb *iocb, long ret, long ret2) +{ + struct nvmet_req *req = container_of(iocb, struct nvmet_req, f.iocb); + + if (req->f.bvec != req->inline_bvec) { + if (likely(req->f.mpool_alloc == false)) + kfree(req->f.bvec); + else + mempool_free(req->f.bvec, req->ns->bvec_pool); + } + + nvmet_req_complete(req, ret != req->data_len ? + NVME_SC_INTERNAL | NVME_SC_DNR : 0); +} + +static void nvmet_file_execute_rw(struct nvmet_req *req) +{ + ssize_t nr_bvec = DIV_ROUND_UP(req->data_len, PAGE_SIZE); + struct sg_page_iter sg_pg_iter; + unsigned long bv_cnt = 0; + bool is_sync = false; + size_t len = 0, total_len = 0; + ssize_t ret = 0; + loff_t pos; + + if (!req->sg_cnt || !nr_bvec) { + nvmet_req_complete(req, 0); + return; + } + + if (nr_bvec > NVMET_MAX_INLINE_BIOVEC) + req->f.bvec = kmalloc_array(nr_bvec, sizeof(struct bio_vec), + GFP_KERNEL); + else + req->f.bvec = req->inline_bvec; + + req->f.mpool_alloc = false; + if (unlikely(!req->f.bvec)) { + /* fallback under memory pressure */ + req->f.bvec = mempool_alloc(req->ns->bvec_pool, GFP_KERNEL); + req->f.mpool_alloc = true; + if (nr_bvec > NVMET_MAX_MPOOL_BVEC) + is_sync = true; + } + + pos = le64_to_cpu(req->cmd->rw.slba) << req->ns->blksize_shift; + + memset(&req->f.iocb, 0, sizeof(struct kiocb)); + for_each_sg_page(req->sg, &sg_pg_iter, req->sg_cnt, 0) { + nvmet_file_init_bvec(&req->f.bvec[bv_cnt], &sg_pg_iter); + len += req->f.bvec[bv_cnt].bv_len; + total_len += req->f.bvec[bv_cnt].bv_len; + bv_cnt++; + + WARN_ON_ONCE((nr_bvec - 1) < 0); + + if (unlikely(is_sync) && + (nr_bvec - 1 == 0 || bv_cnt == NVMET_MAX_MPOOL_BVEC)) { + ret = nvmet_file_submit_bvec(req, pos, bv_cnt, len); + if (ret < 0) + goto out; + pos += len; + bv_cnt = 0; + len = 0; + } + nr_bvec--; + } + + if (WARN_ON_ONCE(total_len != req->data_len)) + ret = -EIO; +out: + if (unlikely(is_sync || ret)) { + nvmet_file_io_done(&req->f.iocb, ret < 0 ? ret : total_len, 0); + return; + } + req->f.iocb.ki_complete = nvmet_file_io_done; + nvmet_file_submit_bvec(req, pos, bv_cnt, total_len); +} + +static void nvmet_file_flush_work(struct work_struct *w) +{ + struct nvmet_req *req = container_of(w, struct nvmet_req, f.work); + int ret; + + ret = vfs_fsync(req->ns->file, 1); + + nvmet_req_complete(req, ret < 0 ? NVME_SC_INTERNAL | NVME_SC_DNR : 0); +} + +static void nvmet_file_execute_flush(struct nvmet_req *req) +{ + INIT_WORK(&req->f.work, nvmet_file_flush_work); + schedule_work(&req->f.work); +} + +static void nvmet_file_execute_discard(struct nvmet_req *req) +{ + int mode = FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE; + struct nvme_dsm_range range; + loff_t offset; + loff_t len; + int i, ret; + + for (i = 0; i <= le32_to_cpu(req->cmd->dsm.nr); i++) { + if (nvmet_copy_from_sgl(req, i * sizeof(range), &range, + sizeof(range))) + break; + offset = le64_to_cpu(range.slba) << req->ns->blksize_shift; + len = le32_to_cpu(range.nlb) << req->ns->blksize_shift; + ret = vfs_fallocate(req->ns->file, mode, offset, len); + if (ret) + break; + } + + nvmet_req_complete(req, ret < 0 ? NVME_SC_INTERNAL | NVME_SC_DNR : 0); +} + +static void nvmet_file_dsm_work(struct work_struct *w) +{ + struct nvmet_req *req = container_of(w, struct nvmet_req, f.work); + + switch (le32_to_cpu(req->cmd->dsm.attributes)) { + case NVME_DSMGMT_AD: + nvmet_file_execute_discard(req); + return; + case NVME_DSMGMT_IDR: + case NVME_DSMGMT_IDW: + default: + /* Not supported yet */ + nvmet_req_complete(req, 0); + return; + } +} + +static void nvmet_file_execute_dsm(struct nvmet_req *req) +{ + INIT_WORK(&req->f.work, nvmet_file_dsm_work); + schedule_work(&req->f.work); +} + +static void nvmet_file_write_zeroes_work(struct work_struct *w) +{ + struct nvmet_req *req = container_of(w, struct nvmet_req, f.work); + struct nvme_write_zeroes_cmd *write_zeroes = &req->cmd->write_zeroes; + int mode = FALLOC_FL_ZERO_RANGE | FALLOC_FL_KEEP_SIZE; + loff_t offset; + loff_t len; + int ret; + + offset = le64_to_cpu(write_zeroes->slba) << req->ns->blksize_shift; + len = (((sector_t)le16_to_cpu(write_zeroes->length) + 1) << + req->ns->blksize_shift); + + ret = vfs_fallocate(req->ns->file, mode, offset, len); + nvmet_req_complete(req, ret < 0 ? NVME_SC_INTERNAL | NVME_SC_DNR : 0); +} + +static void nvmet_file_execute_write_zeroes(struct nvmet_req *req) +{ + INIT_WORK(&req->f.work, nvmet_file_write_zeroes_work); + schedule_work(&req->f.work); +} + +u16 nvmet_file_parse_io_cmd(struct nvmet_req *req) +{ + struct nvme_command *cmd = req->cmd; + + switch (cmd->common.opcode) { + case nvme_cmd_read: + case nvme_cmd_write: + req->execute = nvmet_file_execute_rw; + req->data_len = nvmet_rw_len(req); + return 0; + case nvme_cmd_flush: + req->execute = nvmet_file_execute_flush; + req->data_len = 0; + return 0; + case nvme_cmd_dsm: + req->execute = nvmet_file_execute_dsm; + req->data_len = (le32_to_cpu(cmd->dsm.nr) + 1) * + sizeof(struct nvme_dsm_range); + return 0; + case nvme_cmd_write_zeroes: + req->execute = nvmet_file_execute_write_zeroes; + req->data_len = 0; + return 0; + default: + pr_err("unhandled cmd for file ns %d on qid %d\n", + cmd->common.opcode, req->sq->qid); + return NVME_SC_INVALID_OPCODE | NVME_SC_DNR; + } +} diff --git a/drivers/nvme/target/loop.c b/drivers/nvme/target/loop.c index 27a8561c0cb9..1304ec3a7ede 100644 --- a/drivers/nvme/target/loop.c +++ b/drivers/nvme/target/loop.c @@ -45,6 +45,7 @@ struct nvme_loop_ctrl { struct nvme_ctrl ctrl; struct nvmet_ctrl *target_ctrl; + struct nvmet_port *port; }; static inline struct nvme_loop_ctrl *to_loop_ctrl(struct nvme_ctrl *ctrl) @@ -63,7 +64,8 @@ struct nvme_loop_queue { unsigned long flags; }; -static struct nvmet_port *nvmet_loop_port; +static LIST_HEAD(nvme_loop_ports); +static DEFINE_MUTEX(nvme_loop_ports_mutex); static LIST_HEAD(nvme_loop_ctrl_list); static DEFINE_MUTEX(nvme_loop_ctrl_mutex); @@ -146,7 +148,7 @@ nvme_loop_timeout(struct request *rq, bool reserved) /* fail with DNR on admin cmd timeout */ nvme_req(rq)->status = NVME_SC_ABORT_REQ | NVME_SC_DNR; - return BLK_EH_HANDLED; + return BLK_EH_DONE; } static blk_status_t nvme_loop_queue_rq(struct blk_mq_hw_ctx *hctx, @@ -169,12 +171,12 @@ static blk_status_t nvme_loop_queue_rq(struct blk_mq_hw_ctx *hctx, blk_mq_start_request(req); iod->cmd.common.flags |= NVME_CMD_SGL_METABUF; - iod->req.port = nvmet_loop_port; + iod->req.port = queue->ctrl->port; if (!nvmet_req_init(&iod->req, &queue->nvme_cq, &queue->nvme_sq, &nvme_loop_ops)) return BLK_STS_OK; - if (blk_rq_payload_bytes(req)) { + if (blk_rq_nr_phys_segments(req)) { iod->sg_table.sgl = iod->first_sgl; if (sg_alloc_table_chained(&iod->sg_table, blk_rq_nr_phys_segments(req), @@ -517,6 +519,7 @@ static const struct nvme_ctrl_ops nvme_loop_ctrl_ops = { .free_ctrl = nvme_loop_free_ctrl, .submit_async_event = nvme_loop_submit_async_event, .delete_ctrl = nvme_loop_delete_ctrl_host, + .get_address = nvmf_get_address, }; static int nvme_loop_create_io_queues(struct nvme_loop_ctrl *ctrl) @@ -565,6 +568,23 @@ out_destroy_queues: return ret; } +static struct nvmet_port *nvme_loop_find_port(struct nvme_ctrl *ctrl) +{ + struct nvmet_port *p, *found = NULL; + + mutex_lock(&nvme_loop_ports_mutex); + list_for_each_entry(p, &nvme_loop_ports, entry) { + /* if no transport address is specified use the first port */ + if ((ctrl->opts->mask & NVMF_OPT_TRADDR) && + strcmp(ctrl->opts->traddr, p->disc_addr.traddr)) + continue; + found = p; + break; + } + mutex_unlock(&nvme_loop_ports_mutex); + return found; +} + static struct nvme_ctrl *nvme_loop_create_ctrl(struct device *dev, struct nvmf_ctrl_options *opts) { @@ -589,6 +609,7 @@ static struct nvme_ctrl *nvme_loop_create_ctrl(struct device *dev, ctrl->ctrl.sqsize = opts->queue_size - 1; ctrl->ctrl.kato = opts->kato; + ctrl->port = nvme_loop_find_port(&ctrl->ctrl); ctrl->queues = kcalloc(opts->nr_io_queues + 1, sizeof(*ctrl->queues), GFP_KERNEL); @@ -646,27 +667,17 @@ out_put_ctrl: static int nvme_loop_add_port(struct nvmet_port *port) { - /* - * XXX: disalow adding more than one port so - * there is no connection rejections when a - * a subsystem is assigned to a port for which - * loop doesn't have a pointer. - * This scenario would be possible if we allowed - * more than one port to be added and a subsystem - * was assigned to a port other than nvmet_loop_port. - */ - - if (nvmet_loop_port) - return -EPERM; - - nvmet_loop_port = port; + mutex_lock(&nvme_loop_ports_mutex); + list_add_tail(&port->entry, &nvme_loop_ports); + mutex_unlock(&nvme_loop_ports_mutex); return 0; } static void nvme_loop_remove_port(struct nvmet_port *port) { - if (port == nvmet_loop_port) - nvmet_loop_port = NULL; + mutex_lock(&nvme_loop_ports_mutex); + list_del_init(&port->entry); + mutex_unlock(&nvme_loop_ports_mutex); } static const struct nvmet_fabrics_ops nvme_loop_ops = { @@ -682,6 +693,7 @@ static struct nvmf_transport_ops nvme_loop_transport = { .name = "loop", .module = THIS_MODULE, .create_ctrl = nvme_loop_create_ctrl, + .allowed_opts = NVMF_OPT_TRADDR, }; static int __init nvme_loop_init_module(void) diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h index 15fd84ab21f8..480dfe10fad9 100644 --- a/drivers/nvme/target/nvmet.h +++ b/drivers/nvme/target/nvmet.h @@ -30,6 +30,21 @@ #define NVMET_ASYNC_EVENTS 4 #define NVMET_ERROR_LOG_SLOTS 128 + +/* + * Supported optional AENs: + */ +#define NVMET_AEN_CFG_OPTIONAL \ + NVME_AEN_CFG_NS_ATTR + +/* + * Plus mandatory SMART AENs (we'll never send them, but allow enabling them): + */ +#define NVMET_AEN_CFG_ALL \ + (NVME_SMART_CRIT_SPARE | NVME_SMART_CRIT_TEMPERATURE | \ + NVME_SMART_CRIT_RELIABILITY | NVME_SMART_CRIT_MEDIA | \ + NVME_SMART_CRIT_VOLATILE_MEMORY | NVMET_AEN_CFG_OPTIONAL) + /* Helper Macros when NVMe error is NVME_SC_CONNECT_INVALID_PARAM * The 16 bit shift is to set IATTR bit to 1, which means offending * offset starts in the data section of connect() @@ -43,6 +58,7 @@ struct nvmet_ns { struct list_head dev_link; struct percpu_ref ref; struct block_device *bdev; + struct file *file; u32 nsid; u32 blksize_shift; loff_t size; @@ -57,6 +73,8 @@ struct nvmet_ns { struct config_group group; struct completion disable_done; + mempool_t *bvec_pool; + struct kmem_cache *bvec_cache; }; static inline struct nvmet_ns *to_nvmet_ns(struct config_item *item) @@ -82,7 +100,7 @@ struct nvmet_sq { /** * struct nvmet_port - Common structure to keep port * information for the target. - * @entry: List head for holding a list of these elements. + * @entry: Entry into referrals or transport list. * @disc_addr: Address information is stored in a format defined * for a discovery log page entry. * @group: ConfigFS group for this element's folder. @@ -120,6 +138,8 @@ struct nvmet_ctrl { u16 cntlid; u32 kato; + u32 aen_enabled; + unsigned long aen_masked; struct nvmet_req *async_event_cmds[NVMET_ASYNC_EVENTS]; unsigned int nr_async_event_cmds; struct list_head async_events; @@ -132,6 +152,9 @@ struct nvmet_ctrl { const struct nvmet_fabrics_ops *ops; + __le32 *changed_ns_list; + u32 nr_changed_ns; + char subsysnqn[NVMF_NQN_FIELD_LEN]; char hostnqn[NVMF_NQN_FIELD_LEN]; }; @@ -222,8 +245,18 @@ struct nvmet_req { struct nvmet_cq *cq; struct nvmet_ns *ns; struct scatterlist *sg; - struct bio inline_bio; struct bio_vec inline_bvec[NVMET_MAX_INLINE_BIOVEC]; + union { + struct { + struct bio inline_bio; + } b; + struct { + bool mpool_alloc; + struct kiocb iocb; + struct bio_vec *bvec; + struct work_struct work; + } f; + }; int sg_cnt; /* data length as parsed from the command: */ size_t data_len; @@ -263,7 +296,8 @@ struct nvmet_async_event { }; u16 nvmet_parse_connect_cmd(struct nvmet_req *req); -u16 nvmet_parse_io_cmd(struct nvmet_req *req); +u16 nvmet_bdev_parse_io_cmd(struct nvmet_req *req); +u16 nvmet_file_parse_io_cmd(struct nvmet_req *req); u16 nvmet_parse_admin_cmd(struct nvmet_req *req); u16 nvmet_parse_discovery_cmd(struct nvmet_req *req); u16 nvmet_parse_fabrics_cmd(struct nvmet_req *req); @@ -316,6 +350,7 @@ u16 nvmet_copy_to_sgl(struct nvmet_req *req, off_t off, const void *buf, size_t len); u16 nvmet_copy_from_sgl(struct nvmet_req *req, off_t off, void *buf, size_t len); +u16 nvmet_zero_sgl(struct nvmet_req *req, off_t off, size_t len); u32 nvmet_get_log_page_len(struct nvme_command *cmd); @@ -338,4 +373,14 @@ extern struct rw_semaphore nvmet_config_sem; bool nvmet_host_allowed(struct nvmet_req *req, struct nvmet_subsys *subsys, const char *hostnqn); +int nvmet_bdev_ns_enable(struct nvmet_ns *ns); +int nvmet_file_ns_enable(struct nvmet_ns *ns); +void nvmet_bdev_ns_disable(struct nvmet_ns *ns); +void nvmet_file_ns_disable(struct nvmet_ns *ns); + +static inline u32 nvmet_rw_len(struct nvmet_req *req) +{ + return ((u32)le16_to_cpu(req->cmd->rw.length) + 1) << + req->ns->blksize_shift; +} #endif /* _NVMET_H */ diff --git a/drivers/of/device.c b/drivers/of/device.c index 064c818105bd..33d85511d790 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c @@ -76,6 +76,8 @@ int of_device_add(struct platform_device *ofdev) * of_dma_configure - Setup DMA configuration * @dev: Device to apply DMA configuration * @np: Pointer to OF node having DMA configuration + * @force_dma: Whether device is to be set up by of_dma_configure() even if + * DMA capability is not explicitly described by firmware. * * Try to get devices's DMA configuration from DT and update it * accordingly. @@ -84,7 +86,7 @@ int of_device_add(struct platform_device *ofdev) * can use a platform bus notifier and handle BUS_NOTIFY_ADD_DEVICE events * to fix up DMA configuration. */ -int of_dma_configure(struct device *dev, struct device_node *np) +int of_dma_configure(struct device *dev, struct device_node *np, bool force_dma) { u64 dma_addr, paddr, size = 0; int ret; @@ -100,7 +102,7 @@ int of_dma_configure(struct device *dev, struct device_node *np) * DMA configuration regardless of whether "dma-ranges" is * correctly specified or not. */ - if (!dev->bus->force_dma) + if (!force_dma) return ret == -ENODEV ? 0 : ret; dma_addr = offset = 0; diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c index 9a4f4246231d..895c83e0c7b6 100644 --- a/drivers/of/of_reserved_mem.c +++ b/drivers/of/of_reserved_mem.c @@ -353,7 +353,7 @@ int of_reserved_mem_device_init_by_idx(struct device *dev, /* ensure that dma_ops is set for virtual devices * using reserved memory */ - of_dma_configure(dev, np); + of_dma_configure(dev, np, true); dev_info(dev, "assigned reserved memory node %s\n", rmem->name); } else { diff --git a/drivers/opp/core.c b/drivers/opp/core.c index 92fa94a6dcc1..ab2f3fead6b1 100644 --- a/drivers/opp/core.c +++ b/drivers/opp/core.c @@ -33,8 +33,6 @@ LIST_HEAD(opp_tables); /* Lock to allow exclusive modification to the device and opp lists */ DEFINE_MUTEX(opp_table_lock); -static void dev_pm_opp_get(struct dev_pm_opp *opp); - static struct opp_device *_find_opp_dev(const struct device *dev, struct opp_table *opp_table) { @@ -281,6 +279,23 @@ unsigned long dev_pm_opp_get_suspend_opp_freq(struct device *dev) } EXPORT_SYMBOL_GPL(dev_pm_opp_get_suspend_opp_freq); +int _get_opp_count(struct opp_table *opp_table) +{ + struct dev_pm_opp *opp; + int count = 0; + + mutex_lock(&opp_table->lock); + + list_for_each_entry(opp, &opp_table->opp_list, node) { + if (opp->available) + count++; + } + + mutex_unlock(&opp_table->lock); + + return count; +} + /** * dev_pm_opp_get_opp_count() - Get number of opps available in the opp table * @dev: device for which we do this operation @@ -291,25 +306,17 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_suspend_opp_freq); int dev_pm_opp_get_opp_count(struct device *dev) { struct opp_table *opp_table; - struct dev_pm_opp *temp_opp; - int count = 0; + int count; opp_table = _find_opp_table(dev); if (IS_ERR(opp_table)) { count = PTR_ERR(opp_table); dev_dbg(dev, "%s: OPP table not found (%d)\n", __func__, count); - return count; - } - - mutex_lock(&opp_table->lock); - - list_for_each_entry(temp_opp, &opp_table->opp_list, node) { - if (temp_opp->available) - count++; + return 0; } - mutex_unlock(&opp_table->lock); + count = _get_opp_count(opp_table); dev_pm_opp_put_opp_table(opp_table); return count; @@ -892,7 +899,7 @@ static void _opp_kref_release(struct kref *kref) dev_pm_opp_put_opp_table(opp_table); } -static void dev_pm_opp_get(struct dev_pm_opp *opp) +void dev_pm_opp_get(struct dev_pm_opp *opp) { kref_get(&opp->kref); } @@ -985,22 +992,11 @@ static bool _opp_supported_by_regulators(struct dev_pm_opp *opp, return true; } -/* - * Returns: - * 0: On success. And appropriate error message for duplicate OPPs. - * -EBUSY: For OPP with same freq/volt and is available. The callers of - * _opp_add() must return 0 if they receive -EBUSY from it. This is to make - * sure we don't print error messages unnecessarily if different parts of - * kernel try to initialize the OPP table. - * -EEXIST: For OPP with same freq but different volt or is unavailable. This - * should be considered an error by the callers of _opp_add(). - */ -int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, - struct opp_table *opp_table) +static int _opp_is_duplicate(struct device *dev, struct dev_pm_opp *new_opp, + struct opp_table *opp_table, + struct list_head **head) { struct dev_pm_opp *opp; - struct list_head *head; - int ret; /* * Insert new OPP in order of increasing frequency and discard if @@ -1010,17 +1006,14 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, * loop, don't replace it with head otherwise it will become an infinite * loop. */ - mutex_lock(&opp_table->lock); - head = &opp_table->opp_list; - list_for_each_entry(opp, &opp_table->opp_list, node) { if (new_opp->rate > opp->rate) { - head = &opp->node; + *head = &opp->node; continue; } if (new_opp->rate < opp->rate) - break; + return 0; /* Duplicate OPPs */ dev_warn(dev, "%s: duplicate OPPs detected. Existing: freq: %lu, volt: %lu, enabled: %d. New: freq: %lu, volt: %lu, enabled: %d\n", @@ -1029,15 +1022,39 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, new_opp->supplies[0].u_volt, new_opp->available); /* Should we compare voltages for all regulators here ? */ - ret = opp->available && - new_opp->supplies[0].u_volt == opp->supplies[0].u_volt ? -EBUSY : -EEXIST; - - mutex_unlock(&opp_table->lock); - return ret; + return opp->available && + new_opp->supplies[0].u_volt == opp->supplies[0].u_volt ? -EBUSY : -EEXIST; } - if (opp_table->get_pstate) - new_opp->pstate = opp_table->get_pstate(dev, new_opp->rate); + return 0; +} + +/* + * Returns: + * 0: On success. And appropriate error message for duplicate OPPs. + * -EBUSY: For OPP with same freq/volt and is available. The callers of + * _opp_add() must return 0 if they receive -EBUSY from it. This is to make + * sure we don't print error messages unnecessarily if different parts of + * kernel try to initialize the OPP table. + * -EEXIST: For OPP with same freq but different volt or is unavailable. This + * should be considered an error by the callers of _opp_add(). + */ +int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, + struct opp_table *opp_table, bool rate_not_available) +{ + struct list_head *head; + int ret; + + mutex_lock(&opp_table->lock); + head = &opp_table->opp_list; + + if (likely(!rate_not_available)) { + ret = _opp_is_duplicate(dev, new_opp, opp_table, &head); + if (ret) { + mutex_unlock(&opp_table->lock); + return ret; + } + } list_add(&new_opp->node, head); mutex_unlock(&opp_table->lock); @@ -1104,7 +1121,7 @@ int _opp_add_v1(struct opp_table *opp_table, struct device *dev, new_opp->available = true; new_opp->dynamic = dynamic; - ret = _opp_add(dev, new_opp, opp_table); + ret = _opp_add(dev, new_opp, opp_table, false); if (ret) { /* Don't return error for duplicate OPPs */ if (ret == -EBUSY) @@ -1140,7 +1157,6 @@ struct opp_table *dev_pm_opp_set_supported_hw(struct device *dev, const u32 *versions, unsigned int count) { struct opp_table *opp_table; - int ret; opp_table = dev_pm_opp_get_opp_table(dev); if (!opp_table) @@ -1149,29 +1165,20 @@ struct opp_table *dev_pm_opp_set_supported_hw(struct device *dev, /* Make sure there are no concurrent readers while updating opp_table */ WARN_ON(!list_empty(&opp_table->opp_list)); - /* Do we already have a version hierarchy associated with opp_table? */ - if (opp_table->supported_hw) { - dev_err(dev, "%s: Already have supported hardware list\n", - __func__); - ret = -EBUSY; - goto err; - } + /* Another CPU that shares the OPP table has set the property ? */ + if (opp_table->supported_hw) + return opp_table; opp_table->supported_hw = kmemdup(versions, count * sizeof(*versions), GFP_KERNEL); if (!opp_table->supported_hw) { - ret = -ENOMEM; - goto err; + dev_pm_opp_put_opp_table(opp_table); + return ERR_PTR(-ENOMEM); } opp_table->supported_hw_count = count; return opp_table; - -err: - dev_pm_opp_put_opp_table(opp_table); - - return ERR_PTR(ret); } EXPORT_SYMBOL_GPL(dev_pm_opp_set_supported_hw); @@ -1188,12 +1195,6 @@ void dev_pm_opp_put_supported_hw(struct opp_table *opp_table) /* Make sure there are no concurrent readers while updating opp_table */ WARN_ON(!list_empty(&opp_table->opp_list)); - if (!opp_table->supported_hw) { - pr_err("%s: Doesn't have supported hardware list\n", - __func__); - return; - } - kfree(opp_table->supported_hw); opp_table->supported_hw = NULL; opp_table->supported_hw_count = 0; @@ -1215,7 +1216,6 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_put_supported_hw); struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, const char *name) { struct opp_table *opp_table; - int ret; opp_table = dev_pm_opp_get_opp_table(dev); if (!opp_table) @@ -1224,26 +1224,17 @@ struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, const char *name) /* Make sure there are no concurrent readers while updating opp_table */ WARN_ON(!list_empty(&opp_table->opp_list)); - /* Do we already have a prop-name associated with opp_table? */ - if (opp_table->prop_name) { - dev_err(dev, "%s: Already have prop-name %s\n", __func__, - opp_table->prop_name); - ret = -EBUSY; - goto err; - } + /* Another CPU that shares the OPP table has set the property ? */ + if (opp_table->prop_name) + return opp_table; opp_table->prop_name = kstrdup(name, GFP_KERNEL); if (!opp_table->prop_name) { - ret = -ENOMEM; - goto err; + dev_pm_opp_put_opp_table(opp_table); + return ERR_PTR(-ENOMEM); } return opp_table; - -err: - dev_pm_opp_put_opp_table(opp_table); - - return ERR_PTR(ret); } EXPORT_SYMBOL_GPL(dev_pm_opp_set_prop_name); @@ -1260,11 +1251,6 @@ void dev_pm_opp_put_prop_name(struct opp_table *opp_table) /* Make sure there are no concurrent readers while updating opp_table */ WARN_ON(!list_empty(&opp_table->opp_list)); - if (!opp_table->prop_name) { - pr_err("%s: Doesn't have a prop-name\n", __func__); - return; - } - kfree(opp_table->prop_name); opp_table->prop_name = NULL; @@ -1334,11 +1320,9 @@ struct opp_table *dev_pm_opp_set_regulators(struct device *dev, goto err; } - /* Already have regulators set */ - if (opp_table->regulators) { - ret = -EBUSY; - goto err; - } + /* Another CPU that shares the OPP table has set the regulators ? */ + if (opp_table->regulators) + return opp_table; opp_table->regulators = kmalloc_array(count, sizeof(*opp_table->regulators), @@ -1392,10 +1376,8 @@ void dev_pm_opp_put_regulators(struct opp_table *opp_table) { int i; - if (!opp_table->regulators) { - pr_err("%s: Doesn't have regulators set\n", __func__); - return; - } + if (!opp_table->regulators) + goto put_opp_table; /* Make sure there are no concurrent readers while updating opp_table */ WARN_ON(!list_empty(&opp_table->opp_list)); @@ -1409,6 +1391,7 @@ void dev_pm_opp_put_regulators(struct opp_table *opp_table) opp_table->regulators = NULL; opp_table->regulator_count = 0; +put_opp_table: dev_pm_opp_put_opp_table(opp_table); } EXPORT_SYMBOL_GPL(dev_pm_opp_put_regulators); @@ -1494,7 +1477,6 @@ struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev, int (*set_opp)(struct dev_pm_set_opp_data *data)) { struct opp_table *opp_table; - int ret; if (!set_opp) return ERR_PTR(-EINVAL); @@ -1505,24 +1487,15 @@ struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev, /* This should be called before OPPs are initialized */ if (WARN_ON(!list_empty(&opp_table->opp_list))) { - ret = -EBUSY; - goto err; - } - - /* Already have custom set_opp helper */ - if (WARN_ON(opp_table->set_opp)) { - ret = -EBUSY; - goto err; + dev_pm_opp_put_opp_table(opp_table); + return ERR_PTR(-EBUSY); } - opp_table->set_opp = set_opp; + /* Another CPU that shares the OPP table has set the helper ? */ + if (!opp_table->set_opp) + opp_table->set_opp = set_opp; return opp_table; - -err: - dev_pm_opp_put_opp_table(opp_table); - - return ERR_PTR(ret); } EXPORT_SYMBOL_GPL(dev_pm_opp_register_set_opp_helper); @@ -1535,97 +1508,15 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_register_set_opp_helper); */ void dev_pm_opp_unregister_set_opp_helper(struct opp_table *opp_table) { - if (!opp_table->set_opp) { - pr_err("%s: Doesn't have custom set_opp helper set\n", - __func__); - return; - } - /* Make sure there are no concurrent readers while updating opp_table */ WARN_ON(!list_empty(&opp_table->opp_list)); opp_table->set_opp = NULL; - dev_pm_opp_put_opp_table(opp_table); } EXPORT_SYMBOL_GPL(dev_pm_opp_unregister_set_opp_helper); /** - * dev_pm_opp_register_get_pstate_helper() - Register get_pstate() helper. - * @dev: Device for which the helper is getting registered. - * @get_pstate: Helper. - * - * TODO: Remove this callback after the same information is available via Device - * Tree. - * - * This allows a platform to initialize the performance states of individual - * OPPs for its devices, until we get similar information directly from DT. - * - * This must be called before the OPPs are initialized for the device. - */ -struct opp_table *dev_pm_opp_register_get_pstate_helper(struct device *dev, - int (*get_pstate)(struct device *dev, unsigned long rate)) -{ - struct opp_table *opp_table; - int ret; - - if (!get_pstate) - return ERR_PTR(-EINVAL); - - opp_table = dev_pm_opp_get_opp_table(dev); - if (!opp_table) - return ERR_PTR(-ENOMEM); - - /* This should be called before OPPs are initialized */ - if (WARN_ON(!list_empty(&opp_table->opp_list))) { - ret = -EBUSY; - goto err; - } - - /* Already have genpd_performance_state set */ - if (WARN_ON(opp_table->genpd_performance_state)) { - ret = -EBUSY; - goto err; - } - - opp_table->genpd_performance_state = true; - opp_table->get_pstate = get_pstate; - - return opp_table; - -err: - dev_pm_opp_put_opp_table(opp_table); - - return ERR_PTR(ret); -} -EXPORT_SYMBOL_GPL(dev_pm_opp_register_get_pstate_helper); - -/** - * dev_pm_opp_unregister_get_pstate_helper() - Releases resources blocked for - * get_pstate() helper - * @opp_table: OPP table returned from dev_pm_opp_register_get_pstate_helper(). - * - * Release resources blocked for platform specific get_pstate() helper. - */ -void dev_pm_opp_unregister_get_pstate_helper(struct opp_table *opp_table) -{ - if (!opp_table->genpd_performance_state) { - pr_err("%s: Doesn't have performance states set\n", - __func__); - return; - } - - /* Make sure there are no concurrent readers while updating opp_table */ - WARN_ON(!list_empty(&opp_table->opp_list)); - - opp_table->genpd_performance_state = false; - opp_table->get_pstate = NULL; - - dev_pm_opp_put_opp_table(opp_table); -} -EXPORT_SYMBOL_GPL(dev_pm_opp_unregister_get_pstate_helper); - -/** * dev_pm_opp_add() - Add an OPP table from a table definitions * @dev: device for which we do this operation * @freq: Frequency in Hz for this OPP diff --git a/drivers/opp/debugfs.c b/drivers/opp/debugfs.c index b03c03576a62..e6828e5f81b0 100644 --- a/drivers/opp/debugfs.c +++ b/drivers/opp/debugfs.c @@ -77,10 +77,21 @@ int opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table) { struct dentry *pdentry = opp_table->dentry; struct dentry *d; + unsigned long id; char name[25]; /* 20 chars for 64 bit value + 5 (opp:\0) */ - /* Rate is unique to each OPP, use it to give opp-name */ - snprintf(name, sizeof(name), "opp:%lu", opp->rate); + /* + * Get directory name for OPP. + * + * - Normally rate is unique to each OPP, use it to get unique opp-name. + * - For some devices rate isn't available, use index instead. + */ + if (likely(opp->rate)) + id = opp->rate; + else + id = _get_opp_count(opp_table); + + snprintf(name, sizeof(name), "opp:%lu", id); /* Create per-opp directory */ d = debugfs_create_dir(name, pdentry); diff --git a/drivers/opp/of.c b/drivers/opp/of.c index cb716aa2f44b..7af0ddec936b 100644 --- a/drivers/opp/of.c +++ b/drivers/opp/of.c @@ -17,6 +17,7 @@ #include <linux/errno.h> #include <linux/device.h> #include <linux/of_device.h> +#include <linux/pm_domain.h> #include <linux/slab.h> #include <linux/export.h> @@ -250,20 +251,17 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_remove_table); /* Returns opp descriptor node for a device node, caller must * do of_node_put() */ -static struct device_node *_opp_of_get_opp_desc_node(struct device_node *np) +static struct device_node *_opp_of_get_opp_desc_node(struct device_node *np, + int index) { - /* - * There should be only ONE phandle present in "operating-points-v2" - * property. - */ - - return of_parse_phandle(np, "operating-points-v2", 0); + /* "operating-points-v2" can be an array for power domain providers */ + return of_parse_phandle(np, "operating-points-v2", index); } /* Returns opp descriptor node for a device, caller must do of_node_put() */ struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device *dev) { - return _opp_of_get_opp_desc_node(dev->of_node); + return _opp_of_get_opp_desc_node(dev->of_node, 0); } EXPORT_SYMBOL_GPL(dev_pm_opp_of_get_opp_desc_node); @@ -289,9 +287,10 @@ static int _opp_add_static_v2(struct opp_table *opp_table, struct device *dev, struct device_node *np) { struct dev_pm_opp *new_opp; - u64 rate; + u64 rate = 0; u32 val; int ret; + bool rate_not_available = false; new_opp = _opp_allocate(opp_table); if (!new_opp) @@ -299,8 +298,21 @@ static int _opp_add_static_v2(struct opp_table *opp_table, struct device *dev, ret = of_property_read_u64(np, "opp-hz", &rate); if (ret < 0) { - dev_err(dev, "%s: opp-hz not found\n", __func__); - goto free_opp; + /* "opp-hz" is optional for devices like power domains. */ + if (!of_find_property(dev->of_node, "#power-domain-cells", + NULL)) { + dev_err(dev, "%s: opp-hz not found\n", __func__); + goto free_opp; + } + + rate_not_available = true; + } else { + /* + * Rate is defined as an unsigned long in clk API, and so + * casting explicitly to its type. Must be fixed once rate is 64 + * bit guaranteed in clk API. + */ + new_opp->rate = (unsigned long)rate; } /* Check if the OPP supports hardware's hierarchy of versions or not */ @@ -309,12 +321,6 @@ static int _opp_add_static_v2(struct opp_table *opp_table, struct device *dev, goto free_opp; } - /* - * Rate is defined as an unsigned long in clk API, and so casting - * explicitly to its type. Must be fixed once rate is 64 bit - * guaranteed in clk API. - */ - new_opp->rate = (unsigned long)rate; new_opp->turbo = of_property_read_bool(np, "turbo-mode"); new_opp->np = np; @@ -324,11 +330,13 @@ static int _opp_add_static_v2(struct opp_table *opp_table, struct device *dev, if (!of_property_read_u32(np, "clock-latency-ns", &val)) new_opp->clock_latency_ns = val; + new_opp->pstate = of_genpd_opp_to_performance_state(dev, np); + ret = opp_parse_supplies(new_opp, dev, opp_table); if (ret) goto free_opp; - ret = _opp_add(dev, new_opp, opp_table); + ret = _opp_add(dev, new_opp, opp_table, rate_not_available); if (ret) { /* Don't return error for duplicate OPPs */ if (ret == -EBUSY) @@ -374,7 +382,8 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np) { struct device_node *np; struct opp_table *opp_table; - int ret = 0, count = 0; + int ret = 0, count = 0, pstate_count = 0; + struct dev_pm_opp *opp; opp_table = _managed_opp(opp_np); if (opp_table) { @@ -408,6 +417,20 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np) goto put_opp_table; } + list_for_each_entry(opp, &opp_table->opp_list, node) + pstate_count += !!opp->pstate; + + /* Either all or none of the nodes shall have performance state set */ + if (pstate_count && pstate_count != count) { + dev_err(dev, "Not all nodes have performance state set (%d: %d)\n", + count, pstate_count); + ret = -ENOENT; + goto put_opp_table; + } + + if (pstate_count) + opp_table->genpd_performance_state = true; + opp_table->np = opp_np; if (of_property_read_bool(opp_np, "opp-shared")) opp_table->shared_opp = OPP_TABLE_ACCESS_SHARED; @@ -509,6 +532,54 @@ int dev_pm_opp_of_add_table(struct device *dev) } EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table); +/** + * dev_pm_opp_of_add_table_indexed() - Initialize indexed opp table from device tree + * @dev: device pointer used to lookup OPP table. + * @index: Index number. + * + * Register the initial OPP table with the OPP library for given device only + * using the "operating-points-v2" property. + * + * Return: + * 0 On success OR + * Duplicate OPPs (both freq and volt are same) and opp->available + * -EEXIST Freq are same and volt are different OR + * Duplicate OPPs (both freq and volt are same) and !opp->available + * -ENOMEM Memory allocation failure + * -ENODEV when 'operating-points' property is not found or is invalid data + * in device node. + * -ENODATA when empty 'operating-points' property is found + * -EINVAL when invalid entries are found in opp-v2 table + */ +int dev_pm_opp_of_add_table_indexed(struct device *dev, int index) +{ + struct device_node *opp_np; + int ret, count; + +again: + opp_np = _opp_of_get_opp_desc_node(dev->of_node, index); + if (!opp_np) { + /* + * If only one phandle is present, then the same OPP table + * applies for all index requests. + */ + count = of_count_phandle_with_args(dev->of_node, + "operating-points-v2", NULL); + if (count == 1 && index) { + index = 0; + goto again; + } + + return -ENODEV; + } + + ret = _of_add_opp_table_v2(dev, opp_np); + of_node_put(opp_np); + + return ret; +} +EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table_indexed); + /* CPU device specific helpers */ /** @@ -613,7 +684,7 @@ int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, } /* Get OPP descriptor node */ - tmp_np = _opp_of_get_opp_desc_node(cpu_np); + tmp_np = _opp_of_get_opp_desc_node(cpu_np, 0); of_node_put(cpu_np); if (!tmp_np) { pr_err("%pOF: Couldn't find opp node\n", cpu_np); @@ -633,3 +704,76 @@ put_cpu_node: return ret; } EXPORT_SYMBOL_GPL(dev_pm_opp_of_get_sharing_cpus); + +/** + * of_dev_pm_opp_find_required_opp() - Search for required OPP. + * @dev: The device whose OPP node is referenced by the 'np' DT node. + * @np: Node that contains the "required-opps" property. + * + * Returns the OPP of the device 'dev', whose phandle is present in the "np" + * node. Although the "required-opps" property supports having multiple + * phandles, this helper routine only parses the very first phandle in the list. + * + * Return: Matching opp, else returns ERR_PTR in case of error and should be + * handled using IS_ERR. + * + * The callers are required to call dev_pm_opp_put() for the returned OPP after + * use. + */ +struct dev_pm_opp *of_dev_pm_opp_find_required_opp(struct device *dev, + struct device_node *np) +{ + struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ENODEV); + struct device_node *required_np; + struct opp_table *opp_table; + + opp_table = _find_opp_table(dev); + if (IS_ERR(opp_table)) + return ERR_CAST(opp_table); + + required_np = of_parse_phandle(np, "required-opps", 0); + if (unlikely(!required_np)) { + dev_err(dev, "Unable to parse required-opps\n"); + goto put_opp_table; + } + + mutex_lock(&opp_table->lock); + + list_for_each_entry(temp_opp, &opp_table->opp_list, node) { + if (temp_opp->available && temp_opp->np == required_np) { + opp = temp_opp; + + /* Increment the reference count of OPP */ + dev_pm_opp_get(opp); + break; + } + } + + mutex_unlock(&opp_table->lock); + + of_node_put(required_np); +put_opp_table: + dev_pm_opp_put_opp_table(opp_table); + + return opp; +} +EXPORT_SYMBOL_GPL(of_dev_pm_opp_find_required_opp); + +/** + * dev_pm_opp_get_of_node() - Gets the DT node corresponding to an opp + * @opp: opp for which DT node has to be returned for + * + * Return: DT node corresponding to the opp, else 0 on success. + * + * The caller needs to put the node with of_node_put() after using it. + */ +struct device_node *dev_pm_opp_get_of_node(struct dev_pm_opp *opp) +{ + if (IS_ERR_OR_NULL(opp)) { + pr_err("%s: Invalid parameters\n", __func__); + return NULL; + } + + return of_node_get(opp->np); +} +EXPORT_SYMBOL_GPL(dev_pm_opp_get_of_node); diff --git a/drivers/opp/opp.h b/drivers/opp/opp.h index 4d00061648a3..7c540fd063b2 100644 --- a/drivers/opp/opp.h +++ b/drivers/opp/opp.h @@ -140,7 +140,6 @@ enum opp_table_access { * @genpd_performance_state: Device's power domain support performance state. * @set_opp: Platform specific set_opp callback * @set_opp_data: Data to be passed to set_opp callback - * @get_pstate: Platform specific get_pstate callback * @dentry: debugfs dentry pointer of the real device directory (not links). * @dentry_name: Name of the real dentry. * @@ -178,7 +177,6 @@ struct opp_table { int (*set_opp)(struct dev_pm_set_opp_data *data); struct dev_pm_set_opp_data *set_opp_data; - int (*get_pstate)(struct device *dev, unsigned long rate); #ifdef CONFIG_DEBUG_FS struct dentry *dentry; @@ -187,14 +185,16 @@ struct opp_table { }; /* Routines internal to opp core */ +void dev_pm_opp_get(struct dev_pm_opp *opp); void _get_opp_table_kref(struct opp_table *opp_table); +int _get_opp_count(struct opp_table *opp_table); struct opp_table *_find_opp_table(struct device *dev); struct opp_device *_add_opp_dev(const struct device *dev, struct opp_table *opp_table); void _dev_pm_opp_remove_table(struct opp_table *opp_table, struct device *dev, bool remove_all); void _dev_pm_opp_find_and_remove_table(struct device *dev, bool remove_all); struct dev_pm_opp *_opp_allocate(struct opp_table *opp_table); void _opp_free(struct dev_pm_opp *opp); -int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table); +int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table, bool rate_not_available); int _opp_add_v1(struct opp_table *opp_table, struct device *dev, unsigned long freq, long u_volt, bool dynamic); void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, bool of); struct opp_table *_add_opp_table(struct device *dev); diff --git a/drivers/parisc/Kconfig b/drivers/parisc/Kconfig index 3a102a84d637..5a48b5606110 100644 --- a/drivers/parisc/Kconfig +++ b/drivers/parisc/Kconfig @@ -103,11 +103,6 @@ config IOMMU_SBA depends on PCI_LBA default PCI_LBA -config IOMMU_HELPER - bool - depends on IOMMU_SBA || IOMMU_CCIO - default y - source "drivers/pcmcia/Kconfig" endmenu diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c index 297599fcbc32..614823617b8b 100644 --- a/drivers/parisc/ccio-dma.c +++ b/drivers/parisc/ccio-dma.c @@ -1108,19 +1108,6 @@ static int ccio_proc_info(struct seq_file *m, void *p) return 0; } -static int ccio_proc_info_open(struct inode *inode, struct file *file) -{ - return single_open(file, &ccio_proc_info, NULL); -} - -static const struct file_operations ccio_proc_info_fops = { - .owner = THIS_MODULE, - .open = ccio_proc_info_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static int ccio_proc_bitmap_info(struct seq_file *m, void *p) { struct ioc *ioc = ioc_list; @@ -1135,19 +1122,6 @@ static int ccio_proc_bitmap_info(struct seq_file *m, void *p) return 0; } - -static int ccio_proc_bitmap_open(struct inode *inode, struct file *file) -{ - return single_open(file, &ccio_proc_bitmap_info, NULL); -} - -static const struct file_operations ccio_proc_bitmap_fops = { - .owner = THIS_MODULE, - .open = ccio_proc_bitmap_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; #endif /* CONFIG_PROC_FS */ /** @@ -1589,15 +1563,13 @@ static int __init ccio_probe(struct parisc_device *dev) #ifdef CONFIG_PROC_FS if (ioc_count == 0) { - proc_create(MODULE_NAME, 0, proc_runway_root, - &ccio_proc_info_fops); - proc_create(MODULE_NAME"-bitmap", 0, proc_runway_root, - &ccio_proc_bitmap_fops); + proc_create_single(MODULE_NAME, 0, proc_runway_root, + ccio_proc_info); + proc_create_single(MODULE_NAME"-bitmap", 0, proc_runway_root, + ccio_proc_bitmap_info); } #endif ioc_count++; - - parisc_has_iommu(); return 0; } diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index 0a9c762a70fa..11de0eccf968 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -1864,20 +1864,6 @@ static int sba_proc_info(struct seq_file *m, void *p) } static int -sba_proc_open(struct inode *i, struct file *f) -{ - return single_open(f, &sba_proc_info, NULL); -} - -static const struct file_operations sba_proc_fops = { - .owner = THIS_MODULE, - .open = sba_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int sba_proc_bitmap_info(struct seq_file *m, void *p) { struct sba_device *sba_dev = sba_list; @@ -1889,20 +1875,6 @@ sba_proc_bitmap_info(struct seq_file *m, void *p) return 0; } - -static int -sba_proc_bitmap_open(struct inode *i, struct file *f) -{ - return single_open(f, &sba_proc_bitmap_info, NULL); -} - -static const struct file_operations sba_proc_bitmap_fops = { - .owner = THIS_MODULE, - .open = sba_proc_bitmap_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; #endif /* CONFIG_PROC_FS */ static const struct parisc_device_id sba_tbl[] __initconst = { @@ -2014,11 +1986,9 @@ static int __init sba_driver_callback(struct parisc_device *dev) break; } - proc_create("sba_iommu", 0, root, &sba_proc_fops); - proc_create("sba_iommu-bitmap", 0, root, &sba_proc_bitmap_fops); + proc_create_single("sba_iommu", 0, root, sba_proc_info); + proc_create_single("sba_iommu-bitmap", 0, root, sba_proc_bitmap_info); #endif - - parisc_has_iommu(); return 0; } diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 34b56a8f8480..29a487f31dae 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -5,10 +5,6 @@ source "drivers/pci/pcie/Kconfig" -config PCI_BUS_ADDR_T_64BIT - def_bool y if (ARCH_DMA_ADDR_T_64BIT || 64BIT) - depends on PCI - config PCI_MSI bool "Message Signaled Interrupts (MSI and MSI-X)" depends on PCI diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index bc2ded4c451f..35b7fc87eac5 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -120,7 +120,7 @@ int devm_request_pci_bus_resources(struct device *dev, EXPORT_SYMBOL_GPL(devm_request_pci_bus_resources); static struct pci_bus_region pci_32_bit = {0, 0xffffffffULL}; -#ifdef CONFIG_PCI_BUS_ADDR_T_64BIT +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT static struct pci_bus_region pci_64_bit = {0, (pci_bus_addr_t) 0xffffffffffffffffULL}; static struct pci_bus_region pci_high = {(pci_bus_addr_t) 0x100000000ULL, @@ -230,7 +230,7 @@ int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, resource_size_t), void *alignf_data) { -#ifdef CONFIG_PCI_BUS_ADDR_T_64BIT +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT int rc; if (res->flags & IORESOURCE_MEM_64) { diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 30250631efe7..f45b74fcc059 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -1434,6 +1434,9 @@ struct irq_domain *pci_msi_create_irq_domain(struct fwnode_handle *fwnode, { struct irq_domain *domain; + if (WARN_ON(info->flags & MSI_FLAG_LEVEL_CAPABLE)) + info->flags &= ~MSI_FLAG_LEVEL_CAPABLE; + if (info->flags & MSI_FLAG_USE_DEF_DOM_OPS) pci_msi_domain_update_dom_ops(info); if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index b9a131137e64..18ba62c76480 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -16,6 +16,8 @@ #include <linux/pm_runtime.h> #include <linux/suspend.h> #include <linux/kexec.h> +#include <linux/of_device.h> +#include <linux/acpi.h> #include "pci.h" #include "pcie/portdrv.h" @@ -753,10 +755,11 @@ static int pci_pm_suspend(struct device *dev) * better to resume the device from runtime suspend here. */ if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) || - !pci_dev_keep_suspended(pci_dev)) + !pci_dev_keep_suspended(pci_dev)) { pm_runtime_resume(dev); + pci_dev->state_saved = false; + } - pci_dev->state_saved = false; if (pm->suspend) { pci_power_t prev = pci_dev->current_state; int error; @@ -1577,6 +1580,35 @@ static int pci_bus_num_vf(struct device *dev) return pci_num_vf(to_pci_dev(dev)); } +/** + * pci_dma_configure - Setup DMA configuration + * @dev: ptr to dev structure + * + * Function to update PCI devices's DMA configuration using the same + * info from the OF node or ACPI node of host bridge's parent (if any). + */ +static int pci_dma_configure(struct device *dev) +{ + struct device *bridge; + int ret = 0; + + bridge = pci_get_host_bridge_device(to_pci_dev(dev)); + + if (IS_ENABLED(CONFIG_OF) && bridge->parent && + bridge->parent->of_node) { + ret = of_dma_configure(dev, bridge->parent->of_node, true); + } else if (has_acpi_companion(bridge)) { + struct acpi_device *adev = to_acpi_device_node(bridge->fwnode); + enum dev_dma_attr attr = acpi_get_dma_attr(adev); + + if (attr != DEV_DMA_NOT_SUPPORTED) + ret = acpi_dma_configure(dev, attr); + } + + pci_put_host_bridge_device(bridge); + return ret; +} + struct bus_type pci_bus_type = { .name = "pci", .match = pci_bus_match, @@ -1589,7 +1621,7 @@ struct bus_type pci_bus_type = { .drv_groups = pci_drv_groups, .pm = PCI_PM_OPS_PTR, .num_vf = pci_bus_num_vf, - .force_dma = true, + .dma_configure = pci_dma_configure, }; EXPORT_SYMBOL(pci_bus_type); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index dbfe7c4f3776..e90cf5c32e14 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2025,8 +2025,7 @@ static pci_power_t pci_target_state(struct pci_dev *dev, bool wakeup) if (platform_pci_power_manageable(dev)) { /* - * Call the platform to choose the target state of the device - * and enable wake-up from this state if supported. + * Call the platform to find the target state for the device. */ pci_power_t state = platform_pci_choose_state(dev); @@ -2059,8 +2058,7 @@ static pci_power_t pci_target_state(struct pci_dev *dev, bool wakeup) if (wakeup) { /* * Find the deepest state from which the device can generate - * wake-up events, make it the target state and enable device - * to generate PME#. + * PME#. */ if (dev->pme_support) { while (target_state diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index 1ee8927a0635..7ac035af39f0 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -435,25 +435,12 @@ int pci_proc_detach_bus(struct pci_bus *bus) return 0; } -static int proc_bus_pci_dev_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &proc_bus_pci_devices_op); -} - -static const struct file_operations proc_bus_pci_dev_operations = { - .owner = THIS_MODULE, - .open = proc_bus_pci_dev_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - static int __init pci_proc_init(void) { struct pci_dev *dev = NULL; proc_bus_pci_dir = proc_mkdir("bus/pci", NULL); - proc_create("devices", 0, proc_bus_pci_dir, - &proc_bus_pci_dev_operations); + proc_create_seq("devices", 0, proc_bus_pci_dir, + &proc_bus_pci_devices_op); proc_initialized = 1; for_each_pci_dev(dev) pci_proc_attach_device(dev); diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.c b/drivers/pinctrl/stm32/pinctrl-stm32.c index 6cbcff42ba47..dfed60982a8a 100644 --- a/drivers/pinctrl/stm32/pinctrl-stm32.c +++ b/drivers/pinctrl/stm32/pinctrl-stm32.c @@ -267,12 +267,13 @@ static void stm32_gpio_irq_release_resources(struct irq_data *irq_data) } static struct irq_chip stm32_gpio_irq_chip = { - .name = "stm32gpio", - .irq_ack = irq_chip_ack_parent, - .irq_mask = irq_chip_mask_parent, - .irq_unmask = irq_chip_unmask_parent, - .irq_set_type = irq_chip_set_type_parent, - .irq_set_wake = irq_chip_set_wake_parent, + .name = "stm32gpio", + .irq_eoi = irq_chip_eoi_parent, + .irq_ack = irq_chip_ack_parent, + .irq_mask = irq_chip_mask_parent, + .irq_unmask = irq_chip_unmask_parent, + .irq_set_type = irq_chip_set_type_parent, + .irq_set_wake = irq_chip_set_wake_parent, .irq_request_resources = stm32_gpio_irq_request_resources, .irq_release_resources = stm32_gpio_irq_release_resources, }; diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig index e728a96cabfd..cb0df9eb3e0f 100644 --- a/drivers/platform/chrome/Kconfig +++ b/drivers/platform/chrome/Kconfig @@ -38,6 +38,17 @@ config CHROMEOS_PSTORE If you have a supported Chromebook, choose Y or M here. The module will be called chromeos_pstore. +config CHROMEOS_TBMC + tristate "ChromeOS Tablet Switch Controller" + depends on ACPI + depends on INPUT + help + This option adds a driver for the tablet switch on + select Chrome OS systems. + + To compile this driver as a module, choose M here: the + module will be called chromeos_tbmc. + config CROS_EC_CTL tristate diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile index ff3b369911f0..e44c37a63fa9 100644 --- a/drivers/platform/chrome/Makefile +++ b/drivers/platform/chrome/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o obj-$(CONFIG_CHROMEOS_PSTORE) += chromeos_pstore.o +obj-$(CONFIG_CHROMEOS_TBMC) += chromeos_tbmc.o cros_ec_ctl-objs := cros_ec_sysfs.o cros_ec_lightbar.o \ cros_ec_vbc.o cros_ec_debugfs.o obj-$(CONFIG_CROS_EC_CTL) += cros_ec_ctl.o diff --git a/drivers/platform/chrome/chromeos_laptop.c b/drivers/platform/chrome/chromeos_laptop.c index 5c47f451e43b..24326eecd787 100644 --- a/drivers/platform/chrome/chromeos_laptop.c +++ b/drivers/platform/chrome/chromeos_laptop.c @@ -6,6 +6,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/acpi.h> #include <linux/dmi.h> #include <linux/i2c.h> #include <linux/input.h> @@ -54,6 +55,11 @@ struct i2c_peripheral { struct i2c_client *client; }; +struct acpi_peripheral { + char hid[ACPI_ID_LEN]; + const struct property_entry *properties; +}; + struct chromeos_laptop { /* * Note that we can't mark this pointer as const because @@ -61,6 +67,9 @@ struct chromeos_laptop { */ struct i2c_peripheral *i2c_peripherals; unsigned int num_i2c_peripherals; + + const struct acpi_peripheral *acpi_peripherals; + unsigned int num_acpi_peripherals; }; static const struct chromeos_laptop *cros_laptop; @@ -148,6 +157,38 @@ static void chromeos_laptop_check_adapter(struct i2c_adapter *adapter) } } +static bool chromeos_laptop_adjust_client(struct i2c_client *client) +{ + const struct acpi_peripheral *acpi_dev; + struct acpi_device_id acpi_ids[2] = { }; + int i; + int error; + + if (!has_acpi_companion(&client->dev)) + return false; + + for (i = 0; i < cros_laptop->num_acpi_peripherals; i++) { + acpi_dev = &cros_laptop->acpi_peripherals[i]; + + memcpy(acpi_ids[0].id, acpi_dev->hid, ACPI_ID_LEN); + + if (acpi_match_device(acpi_ids, &client->dev)) { + error = device_add_properties(&client->dev, + acpi_dev->properties); + if (error) { + dev_err(&client->dev, + "failed to add properties: %d\n", + error); + break; + } + + return true; + } + } + + return false; +} + static void chromeos_laptop_detach_i2c_client(struct i2c_client *client) { struct i2c_peripheral *i2c_dev; @@ -170,6 +211,8 @@ static int chromeos_laptop_i2c_notifier_call(struct notifier_block *nb, case BUS_NOTIFY_ADD_DEVICE: if (dev->type == &i2c_adapter_type) chromeos_laptop_check_adapter(to_i2c_adapter(dev)); + else if (dev->type == &i2c_client_type) + chromeos_laptop_adjust_client(to_i2c_client(dev)); break; case BUS_NOTIFY_REMOVED_DEVICE: @@ -191,6 +234,12 @@ static const struct chromeos_laptop _name __initconst = { \ .num_i2c_peripherals = ARRAY_SIZE(_name##_peripherals), \ } +#define DECLARE_ACPI_CROS_LAPTOP(_name) \ +static const struct chromeos_laptop _name __initconst = { \ + .acpi_peripherals = _name##_peripherals, \ + .num_acpi_peripherals = ARRAY_SIZE(_name##_peripherals), \ +} + static struct i2c_peripheral samsung_series_5_550_peripherals[] __initdata = { /* Touchpad. */ { @@ -234,16 +283,25 @@ static const int chromebook_pixel_tp_keys[] __initconst = { static const struct property_entry chromebook_pixel_trackpad_props[] __initconst = { + PROPERTY_ENTRY_STRING("compatible", "atmel,maxtouch"), PROPERTY_ENTRY_U32_ARRAY("linux,gpio-keymap", chromebook_pixel_tp_keys), { } }; +static const struct property_entry +chromebook_atmel_touchscreen_props[] __initconst = { + PROPERTY_ENTRY_STRING("compatible", "atmel,maxtouch"), + { } +}; + static struct i2c_peripheral chromebook_pixel_peripherals[] __initdata = { /* Touch Screen. */ { .board_info = { I2C_BOARD_INFO("atmel_mxt_ts", ATMEL_TS_I2C_ADDR), + .properties = + chromebook_atmel_touchscreen_props, .flags = I2C_CLIENT_WAKE, }, .dmi_name = "touchscreen", @@ -354,6 +412,8 @@ static struct i2c_peripheral acer_c720_peripherals[] __initdata = { .board_info = { I2C_BOARD_INFO("atmel_mxt_ts", ATMEL_TS_I2C_ADDR), + .properties = + chromebook_atmel_touchscreen_props, .flags = I2C_CLIENT_WAKE, }, .dmi_name = "touchscreen", @@ -419,6 +479,47 @@ static struct i2c_peripheral cr48_peripherals[] __initdata = { }; DECLARE_CROS_LAPTOP(cr48); +static const u32 samus_touchpad_buttons[] __initconst = { + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + BTN_LEFT +}; + +static const struct property_entry samus_trackpad_props[] __initconst = { + PROPERTY_ENTRY_STRING("compatible", "atmel,maxtouch"), + PROPERTY_ENTRY_U32_ARRAY("linux,gpio-keymap", samus_touchpad_buttons), + { } +}; + +static struct acpi_peripheral samus_peripherals[] __initdata = { + /* Touchpad */ + { + .hid = "ATML0000", + .properties = samus_trackpad_props, + }, + /* Touchsceen */ + { + .hid = "ATML0001", + .properties = chromebook_atmel_touchscreen_props, + }, +}; +DECLARE_ACPI_CROS_LAPTOP(samus); + +static struct acpi_peripheral generic_atmel_peripherals[] __initdata = { + /* Touchpad */ + { + .hid = "ATML0000", + .properties = chromebook_pixel_trackpad_props, + }, + /* Touchsceen */ + { + .hid = "ATML0001", + .properties = chromebook_atmel_touchscreen_props, + }, +}; +DECLARE_ACPI_CROS_LAPTOP(generic_atmel); + static const struct dmi_system_id chromeos_laptop_dmi_table[] __initconst = { { .ident = "Samsung Series 5 550", @@ -502,17 +603,72 @@ static const struct dmi_system_id chromeos_laptop_dmi_table[] __initconst = { }, .driver_data = (void *)&cr48, }, + /* Devices with peripherals incompletely described in ACPI */ + { + .ident = "Chromebook Pro", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + DMI_MATCH(DMI_PRODUCT_NAME, "Caroline"), + }, + .driver_data = (void *)&samus, + }, + { + .ident = "Google Pixel 2 (2015)", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"), + DMI_MATCH(DMI_PRODUCT_NAME, "Samus"), + }, + .driver_data = (void *)&samus, + }, + { + .ident = "Samsung Chromebook 3", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"), + DMI_MATCH(DMI_PRODUCT_NAME, "Celes"), + }, + .driver_data = (void *)&samus, + }, + { + /* + * Other Chromebooks with Atmel touch controllers: + * - Winky (touchpad) + * - Clapper, Expresso, Rambi, Glimmer (touchscreen) + */ + .ident = "Other Chromebook", + .matches = { + /* + * This will match all Google devices, not only devices + * with Atmel, but we will validate that the device + * actually has matching peripherals. + */ + DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"), + }, + .driver_data = (void *)&generic_atmel, + }, { } }; MODULE_DEVICE_TABLE(dmi, chromeos_laptop_dmi_table); -static int __init chromeos_laptop_scan_adapter(struct device *dev, void *data) +static int __init chromeos_laptop_scan_peripherals(struct device *dev, void *data) { - struct i2c_adapter *adapter; + int error; - adapter = i2c_verify_adapter(dev); - if (adapter) - chromeos_laptop_check_adapter(adapter); + if (dev->type == &i2c_adapter_type) { + chromeos_laptop_check_adapter(to_i2c_adapter(dev)); + } else if (dev->type == &i2c_client_type) { + if (chromeos_laptop_adjust_client(to_i2c_client(dev))) { + /* + * Now that we have needed properties re-trigger + * driver probe in case driver was initialized + * earlier and probe failed. + */ + error = device_attach(dev); + if (error < 0) + dev_warn(dev, + "%s: device_attach() failed: %d\n", + __func__, error); + } + } return 0; } @@ -556,27 +712,24 @@ static int __init chromeos_laptop_setup_irq(struct i2c_peripheral *i2c_dev) return 0; } -static struct chromeos_laptop * __init -chromeos_laptop_prepare(const struct chromeos_laptop *src) +static int __init +chromeos_laptop_prepare_i2c_peripherals(struct chromeos_laptop *cros_laptop, + const struct chromeos_laptop *src) { - struct chromeos_laptop *cros_laptop; struct i2c_peripheral *i2c_dev; struct i2c_board_info *info; - int error; int i; + int error; - cros_laptop = kzalloc(sizeof(*cros_laptop), GFP_KERNEL); - if (!cros_laptop) - return ERR_PTR(-ENOMEM); + if (!src->num_i2c_peripherals) + return 0; cros_laptop->i2c_peripherals = kmemdup(src->i2c_peripherals, src->num_i2c_peripherals * sizeof(*src->i2c_peripherals), GFP_KERNEL); - if (!cros_laptop->i2c_peripherals) { - error = -ENOMEM; - goto err_free_cros_laptop; - } + if (!cros_laptop->i2c_peripherals) + return -ENOMEM; cros_laptop->num_i2c_peripherals = src->num_i2c_peripherals; @@ -586,7 +739,7 @@ chromeos_laptop_prepare(const struct chromeos_laptop *src) error = chromeos_laptop_setup_irq(i2c_dev); if (error) - goto err_destroy_cros_peripherals; + goto err_out; /* We need to deep-copy properties */ if (info->properties) { @@ -594,14 +747,14 @@ chromeos_laptop_prepare(const struct chromeos_laptop *src) property_entries_dup(info->properties); if (IS_ERR(info->properties)) { error = PTR_ERR(info->properties); - goto err_destroy_cros_peripherals; + goto err_out; } } } - return cros_laptop; + return 0; -err_destroy_cros_peripherals: +err_out: while (--i >= 0) { i2c_dev = &cros_laptop->i2c_peripherals[i]; info = &i2c_dev->board_info; @@ -609,13 +762,74 @@ err_destroy_cros_peripherals: property_entries_free(info->properties); } kfree(cros_laptop->i2c_peripherals); -err_free_cros_laptop: - kfree(cros_laptop); - return ERR_PTR(error); + return error; +} + +static int __init +chromeos_laptop_prepare_acpi_peripherals(struct chromeos_laptop *cros_laptop, + const struct chromeos_laptop *src) +{ + struct acpi_peripheral *acpi_peripherals; + struct acpi_peripheral *acpi_dev; + const struct acpi_peripheral *src_dev; + int n_peripherals = 0; + int i; + int error; + + for (i = 0; i < src->num_acpi_peripherals; i++) { + if (acpi_dev_present(src->acpi_peripherals[i].hid, NULL, -1)) + n_peripherals++; + } + + if (!n_peripherals) + return 0; + + acpi_peripherals = kcalloc(n_peripherals, + sizeof(*src->acpi_peripherals), + GFP_KERNEL); + if (!acpi_peripherals) + return -ENOMEM; + + acpi_dev = acpi_peripherals; + for (i = 0; i < src->num_acpi_peripherals; i++) { + src_dev = &src->acpi_peripherals[i]; + if (!acpi_dev_present(src_dev->hid, NULL, -1)) + continue; + + *acpi_dev = *src_dev; + + /* We need to deep-copy properties */ + if (src_dev->properties) { + acpi_dev->properties = + property_entries_dup(src_dev->properties); + if (IS_ERR(acpi_dev->properties)) { + error = PTR_ERR(acpi_dev->properties); + goto err_out; + } + } + + acpi_dev++; + } + + cros_laptop->acpi_peripherals = acpi_peripherals; + cros_laptop->num_acpi_peripherals = n_peripherals; + + return 0; + +err_out: + while (--i >= 0) { + acpi_dev = &acpi_peripherals[i]; + if (acpi_dev->properties) + property_entries_free(acpi_dev->properties); + } + + kfree(acpi_peripherals); + return error; } static void chromeos_laptop_destroy(const struct chromeos_laptop *cros_laptop) { + const struct acpi_peripheral *acpi_dev; struct i2c_peripheral *i2c_dev; struct i2c_board_info *info; int i; @@ -631,10 +845,41 @@ static void chromeos_laptop_destroy(const struct chromeos_laptop *cros_laptop) property_entries_free(info->properties); } + for (i = 0; i < cros_laptop->num_acpi_peripherals; i++) { + acpi_dev = &cros_laptop->acpi_peripherals[i]; + + if (acpi_dev->properties) + property_entries_free(acpi_dev->properties); + } + kfree(cros_laptop->i2c_peripherals); + kfree(cros_laptop->acpi_peripherals); kfree(cros_laptop); } +static struct chromeos_laptop * __init +chromeos_laptop_prepare(const struct chromeos_laptop *src) +{ + struct chromeos_laptop *cros_laptop; + int error; + + cros_laptop = kzalloc(sizeof(*cros_laptop), GFP_KERNEL); + if (!cros_laptop) + return ERR_PTR(-ENOMEM); + + error = chromeos_laptop_prepare_i2c_peripherals(cros_laptop, src); + if (!error) + error = chromeos_laptop_prepare_acpi_peripherals(cros_laptop, + src); + + if (error) { + chromeos_laptop_destroy(cros_laptop); + return ERR_PTR(error); + } + + return cros_laptop; +} + static int __init chromeos_laptop_init(void) { const struct dmi_system_id *dmi_id; @@ -652,21 +897,33 @@ static int __init chromeos_laptop_init(void) if (IS_ERR(cros_laptop)) return PTR_ERR(cros_laptop); + if (!cros_laptop->num_i2c_peripherals && + !cros_laptop->num_acpi_peripherals) { + pr_debug("no relevant devices detected\n"); + error = -ENODEV; + goto err_destroy_cros_laptop; + } + error = bus_register_notifier(&i2c_bus_type, &chromeos_laptop_i2c_notifier); if (error) { - pr_err("failed to register i2c bus notifier: %d\n", error); - chromeos_laptop_destroy(cros_laptop); - return error; + pr_err("failed to register i2c bus notifier: %d\n", + error); + goto err_destroy_cros_laptop; } /* - * Scan adapters that have been registered before we installed - * the notifier to make sure we do not miss any devices. + * Scan adapters that have been registered and clients that have + * been created before we installed the notifier to make sure + * we do not miss any devices. */ - i2c_for_each_dev(NULL, chromeos_laptop_scan_adapter); + i2c_for_each_dev(NULL, chromeos_laptop_scan_peripherals); return 0; + +err_destroy_cros_laptop: + chromeos_laptop_destroy(cros_laptop); + return error; } static void __exit chromeos_laptop_exit(void) diff --git a/drivers/platform/chrome/chromeos_tbmc.c b/drivers/platform/chrome/chromeos_tbmc.c new file mode 100644 index 000000000000..b935df6a9694 --- /dev/null +++ b/drivers/platform/chrome/chromeos_tbmc.c @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Driver to detect Tablet Mode for ChromeOS convertible. +// +// Copyright (C) 2017 Google, Inc. +// Author: Gwendal Grignou <gwendal@chromium.org> + +#include <linux/acpi.h> +#include <linux/input.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/printk.h> + +#define DRV_NAME "chromeos_tbmc" +#define ACPI_DRV_NAME "GOOG0006" + +static int chromeos_tbmc_query_switch(struct acpi_device *adev, + struct input_dev *idev) +{ + unsigned long long state; + acpi_status status; + + status = acpi_evaluate_integer(adev->handle, "TBMC", NULL, &state); + if (ACPI_FAILURE(status)) + return -ENODEV; + + /* input layer checks if event is redundant */ + input_report_switch(idev, SW_TABLET_MODE, state); + input_sync(idev); + + return 0; +} + +static __maybe_unused int chromeos_tbmc_resume(struct device *dev) +{ + struct acpi_device *adev = to_acpi_device(dev); + + return chromeos_tbmc_query_switch(adev, adev->driver_data); +} + +static void chromeos_tbmc_notify(struct acpi_device *adev, u32 event) +{ + switch (event) { + case 0x80: + chromeos_tbmc_query_switch(adev, adev->driver_data); + break; + default: + dev_err(&adev->dev, "Unexpected event: 0x%08X\n", event); + } +} + +static int chromeos_tbmc_open(struct input_dev *idev) +{ + struct acpi_device *adev = input_get_drvdata(idev); + + return chromeos_tbmc_query_switch(adev, idev); +} + +static int chromeos_tbmc_add(struct acpi_device *adev) +{ + struct input_dev *idev; + struct device *dev = &adev->dev; + int ret; + + idev = devm_input_allocate_device(dev); + if (!idev) + return -ENOMEM; + + idev->name = "Tablet Mode Switch"; + idev->phys = acpi_device_hid(adev); + + idev->id.bustype = BUS_HOST; + idev->id.version = 1; + idev->id.product = 0; + idev->open = chromeos_tbmc_open; + + input_set_drvdata(idev, adev); + adev->driver_data = idev; + + input_set_capability(idev, EV_SW, SW_TABLET_MODE); + ret = input_register_device(idev); + if (ret) { + dev_err(dev, "cannot register input device\n"); + return ret; + } + return 0; +} + +static const struct acpi_device_id chromeos_tbmc_acpi_device_ids[] = { + { ACPI_DRV_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(acpi, chromeos_tbmc_acpi_device_ids); + +static const SIMPLE_DEV_PM_OPS(chromeos_tbmc_pm_ops, NULL, + chromeos_tbmc_resume); + +static struct acpi_driver chromeos_tbmc_driver = { + .name = DRV_NAME, + .class = DRV_NAME, + .ids = chromeos_tbmc_acpi_device_ids, + .ops = { + .add = chromeos_tbmc_add, + .notify = chromeos_tbmc_notify, + }, + .drv.pm = &chromeos_tbmc_pm_ops, +}; + +module_acpi_driver(chromeos_tbmc_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("ChromeOS ACPI tablet switch driver"); diff --git a/drivers/platform/chrome/cros_ec_lightbar.c b/drivers/platform/chrome/cros_ec_lightbar.c index 6ea79d495aa2..68193bb53383 100644 --- a/drivers/platform/chrome/cros_ec_lightbar.c +++ b/drivers/platform/chrome/cros_ec_lightbar.c @@ -170,8 +170,7 @@ static ssize_t version_show(struct device *dev, struct device_attribute *attr, char *buf) { uint32_t version = 0, flags = 0; - struct cros_ec_dev *ec = container_of(dev, - struct cros_ec_dev, class_dev); + struct cros_ec_dev *ec = to_cros_ec_dev(dev); int ret; ret = lb_throttle(); @@ -193,8 +192,7 @@ static ssize_t brightness_store(struct device *dev, struct cros_ec_command *msg; int ret; unsigned int val; - struct cros_ec_dev *ec = container_of(dev, - struct cros_ec_dev, class_dev); + struct cros_ec_dev *ec = to_cros_ec_dev(dev); if (kstrtouint(buf, 0, &val)) return -EINVAL; @@ -238,8 +236,7 @@ static ssize_t led_rgb_store(struct device *dev, struct device_attribute *attr, { struct ec_params_lightbar *param; struct cros_ec_command *msg; - struct cros_ec_dev *ec = container_of(dev, - struct cros_ec_dev, class_dev); + struct cros_ec_dev *ec = to_cros_ec_dev(dev); unsigned int val[4]; int ret, i = 0, j = 0, ok = 0; @@ -311,8 +308,7 @@ static ssize_t sequence_show(struct device *dev, struct ec_response_lightbar *resp; struct cros_ec_command *msg; int ret; - struct cros_ec_dev *ec = container_of(dev, - struct cros_ec_dev, class_dev); + struct cros_ec_dev *ec = to_cros_ec_dev(dev); msg = alloc_lightbar_cmd_msg(ec); if (!msg) @@ -439,8 +435,7 @@ static ssize_t sequence_store(struct device *dev, struct device_attribute *attr, struct cros_ec_command *msg; unsigned int num; int ret, len; - struct cros_ec_dev *ec = container_of(dev, - struct cros_ec_dev, class_dev); + struct cros_ec_dev *ec = to_cros_ec_dev(dev); for (len = 0; len < count; len++) if (!isalnum(buf[len])) @@ -488,8 +483,7 @@ static ssize_t program_store(struct device *dev, struct device_attribute *attr, int extra_bytes, max_size, ret; struct ec_params_lightbar *param; struct cros_ec_command *msg; - struct cros_ec_dev *ec = container_of(dev, struct cros_ec_dev, - class_dev); + struct cros_ec_dev *ec = to_cros_ec_dev(dev); /* * We might need to reject the program for size reasons. The EC @@ -599,8 +593,7 @@ static umode_t cros_ec_lightbar_attrs_are_visible(struct kobject *kobj, struct attribute *a, int n) { struct device *dev = container_of(kobj, struct device, kobj); - struct cros_ec_dev *ec = container_of(dev, - struct cros_ec_dev, class_dev); + struct cros_ec_dev *ec = to_cros_ec_dev(dev); struct platform_device *pdev = to_platform_device(ec->dev); struct cros_ec_platform *pdata = pdev->dev.platform_data; int is_cros_ec; diff --git a/drivers/platform/chrome/cros_ec_lpc.c b/drivers/platform/chrome/cros_ec_lpc.c index 3682e1539251..31c8b8c49e45 100644 --- a/drivers/platform/chrome/cros_ec_lpc.c +++ b/drivers/platform/chrome/cros_ec_lpc.c @@ -435,7 +435,13 @@ static int __init cros_ec_lpc_init(void) int ret; acpi_status status; - if (!dmi_check_system(cros_ec_lpc_dmi_table)) { + status = acpi_get_devices(ACPI_DRV_NAME, cros_ec_lpc_parse_device, + &cros_ec_lpc_acpi_device_found, NULL); + if (ACPI_FAILURE(status)) + pr_warn(DRV_NAME ": Looking for %s failed\n", ACPI_DRV_NAME); + + if (!cros_ec_lpc_acpi_device_found && + !dmi_check_system(cros_ec_lpc_dmi_table)) { pr_err(DRV_NAME ": unsupported system.\n"); return -ENODEV; } @@ -450,11 +456,6 @@ static int __init cros_ec_lpc_init(void) return ret; } - status = acpi_get_devices(ACPI_DRV_NAME, cros_ec_lpc_parse_device, - &cros_ec_lpc_acpi_device_found, NULL); - if (ACPI_FAILURE(status)) - pr_warn(DRV_NAME ": Looking for %s failed\n", ACPI_DRV_NAME); - if (!cros_ec_lpc_acpi_device_found) { /* Register the device, and it'll get hooked up automatically */ ret = platform_device_register(&cros_ec_lpc_device); diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c index e7bbdf947bbc..8350ca2311c7 100644 --- a/drivers/platform/chrome/cros_ec_proto.c +++ b/drivers/platform/chrome/cros_ec_proto.c @@ -91,6 +91,8 @@ static int send_command(struct cros_ec_device *ec_dev, usleep_range(10000, 11000); ret = (*xfer_fxn)(ec_dev, status_msg); + if (ret == -EAGAIN) + continue; if (ret < 0) break; diff --git a/drivers/platform/chrome/cros_ec_sysfs.c b/drivers/platform/chrome/cros_ec_sysfs.c index 5a6db3fe213a..f34a50121064 100644 --- a/drivers/platform/chrome/cros_ec_sysfs.c +++ b/drivers/platform/chrome/cros_ec_sysfs.c @@ -34,8 +34,6 @@ #include <linux/types.h> #include <linux/uaccess.h> -#define to_cros_ec_dev(dev) container_of(dev, struct cros_ec_dev, class_dev) - /* Accessor functions */ static ssize_t reboot_show(struct device *dev, diff --git a/drivers/platform/chrome/cros_ec_vbc.c b/drivers/platform/chrome/cros_ec_vbc.c index 6d38e6b08334..5356f26bc022 100644 --- a/drivers/platform/chrome/cros_ec_vbc.c +++ b/drivers/platform/chrome/cros_ec_vbc.c @@ -29,8 +29,7 @@ static ssize_t vboot_context_read(struct file *filp, struct kobject *kobj, loff_t pos, size_t count) { struct device *dev = container_of(kobj, struct device, kobj); - struct cros_ec_dev *ec = container_of(dev, struct cros_ec_dev, - class_dev); + struct cros_ec_dev *ec = to_cros_ec_dev(dev); struct cros_ec_device *ecdev = ec->ec_dev; struct ec_params_vbnvcontext *params; struct cros_ec_command *msg; @@ -70,8 +69,7 @@ static ssize_t vboot_context_write(struct file *filp, struct kobject *kobj, loff_t pos, size_t count) { struct device *dev = container_of(kobj, struct device, kobj); - struct cros_ec_dev *ec = container_of(dev, struct cros_ec_dev, - class_dev); + struct cros_ec_dev *ec = to_cros_ec_dev(dev); struct cros_ec_device *ecdev = ec->ec_dev; struct ec_params_vbnvcontext *params; struct cros_ec_command *msg; @@ -111,8 +109,7 @@ static umode_t cros_ec_vbc_is_visible(struct kobject *kobj, struct bin_attribute *a, int n) { struct device *dev = container_of(kobj, struct device, kobj); - struct cros_ec_dev *ec = container_of(dev, struct cros_ec_dev, - class_dev); + struct cros_ec_dev *ec = to_cros_ec_dev(dev); struct device_node *np = ec->ec_dev->dev->of_node; if (IS_ENABLED(CONFIG_OF) && np) { diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index a32c5c00e0e7..ffffb9909ae1 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -163,6 +163,16 @@ MODULE_LICENSE("GPL"); static const char * const ashs_ids[] = { "ATK4001", "ATK4002", NULL }; +static bool ashs_present(void) +{ + int i = 0; + while (ashs_ids[i]) { + if (acpi_dev_found(ashs_ids[i++])) + return true; + } + return false; +} + struct bios_args { u32 arg0; u32 arg1; @@ -1025,6 +1035,9 @@ static int asus_new_rfkill(struct asus_wmi *asus, static void asus_wmi_rfkill_exit(struct asus_wmi *asus) { + if (asus->driver->wlan_ctrl_by_user && ashs_present()) + return; + asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P5"); asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P6"); asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P7"); @@ -2121,16 +2134,6 @@ static int asus_wmi_fan_init(struct asus_wmi *asus) return 0; } -static bool ashs_present(void) -{ - int i = 0; - while (ashs_ids[i]) { - if (acpi_dev_found(ashs_ids[i++])) - return true; - } - return false; -} - /* * WMI Driver */ diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index e8d058c5ef21..eef76bfa5d73 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -1689,19 +1689,6 @@ static int version_proc_show(struct seq_file *m, void *v) return 0; } -static int version_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, version_proc_show, PDE_DATA(inode)); -} - -static const struct file_operations version_proc_fops = { - .owner = THIS_MODULE, - .open = version_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - /* * Proc and module init */ @@ -1722,8 +1709,8 @@ static void create_toshiba_proc_entries(struct toshiba_acpi_dev *dev) if (dev->hotkey_dev) proc_create_data("keys", S_IRUGO | S_IWUSR, toshiba_proc_dir, &keys_proc_fops, dev); - proc_create_data("version", S_IRUGO, toshiba_proc_dir, - &version_proc_fops, dev); + proc_create_single_data("version", S_IRUGO, toshiba_proc_dir, + version_proc_show, dev); } static void remove_toshiba_proc_entries(struct toshiba_acpi_dev *dev) diff --git a/drivers/pnp/pnpbios/proc.c b/drivers/pnp/pnpbios/proc.c index 7d4aca7948dd..fe1c8f5d9af0 100644 --- a/drivers/pnp/pnpbios/proc.c +++ b/drivers/pnp/pnpbios/proc.c @@ -47,19 +47,6 @@ static int pnpconfig_proc_show(struct seq_file *m, void *v) return 0; } -static int pnpconfig_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, pnpconfig_proc_show, NULL); -} - -static const struct file_operations pnpconfig_proc_fops = { - .owner = THIS_MODULE, - .open = pnpconfig_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static int escd_info_proc_show(struct seq_file *m, void *v) { struct escd_info_struc escd; @@ -74,19 +61,6 @@ static int escd_info_proc_show(struct seq_file *m, void *v) return 0; } -static int escd_info_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, escd_info_proc_show, NULL); -} - -static const struct file_operations escd_info_proc_fops = { - .owner = THIS_MODULE, - .open = escd_info_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - #define MAX_SANE_ESCD_SIZE (32*1024) static int escd_proc_show(struct seq_file *m, void *v) { @@ -129,19 +103,6 @@ static int escd_proc_show(struct seq_file *m, void *v) return 0; } -static int escd_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, escd_proc_show, NULL); -} - -static const struct file_operations escd_proc_fops = { - .owner = THIS_MODULE, - .open = escd_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static int pnp_legacyres_proc_show(struct seq_file *m, void *v) { void *buf; @@ -159,19 +120,6 @@ static int pnp_legacyres_proc_show(struct seq_file *m, void *v) return 0; } -static int pnp_legacyres_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, pnp_legacyres_proc_show, NULL); -} - -static const struct file_operations pnp_legacyres_proc_fops = { - .owner = THIS_MODULE, - .open = pnp_legacyres_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static int pnp_devices_proc_show(struct seq_file *m, void *v) { struct pnp_bios_node *node; @@ -202,19 +150,6 @@ static int pnp_devices_proc_show(struct seq_file *m, void *v) return 0; } -static int pnp_devices_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, pnp_devices_proc_show, NULL); -} - -static const struct file_operations pnp_devices_proc_fops = { - .owner = THIS_MODULE, - .open = pnp_devices_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static int pnpbios_proc_show(struct seq_file *m, void *v) { void *data = m->private; @@ -318,12 +253,13 @@ int __init pnpbios_proc_init(void) proc_pnp_boot = proc_mkdir("boot", proc_pnp); if (!proc_pnp_boot) return -EIO; - proc_create("devices", 0, proc_pnp, &pnp_devices_proc_fops); - proc_create("configuration_info", 0, proc_pnp, &pnpconfig_proc_fops); - proc_create("escd_info", 0, proc_pnp, &escd_info_proc_fops); - proc_create("escd", S_IRUSR, proc_pnp, &escd_proc_fops); - proc_create("legacy_device_resources", 0, proc_pnp, &pnp_legacyres_proc_fops); - + proc_create_single("devices", 0, proc_pnp, pnp_devices_proc_show); + proc_create_single("configuration_info", 0, proc_pnp, + pnpconfig_proc_show); + proc_create_single("escd_info", 0, proc_pnp, escd_info_proc_show); + proc_create_single("escd", S_IRUSR, proc_pnp, escd_proc_show); + proc_create_single("legacy_device_resources", 0, proc_pnp, + pnp_legacyres_proc_show); return 0; } diff --git a/drivers/power/avs/rockchip-io-domain.c b/drivers/power/avs/rockchip-io-domain.c index ed2b109ae8fc..d6a5e6bf5f12 100644 --- a/drivers/power/avs/rockchip-io-domain.c +++ b/drivers/power/avs/rockchip-io-domain.c @@ -39,6 +39,10 @@ #define MAX_VOLTAGE_1_8 1980000 #define MAX_VOLTAGE_3_3 3600000 +#define PX30_IO_VSEL 0x180 +#define PX30_IO_VSEL_VCCIO6_SRC BIT(0) +#define PX30_IO_VSEL_VCCIO6_SUPPLY_NUM 1 + #define RK3288_SOC_CON2 0x24c #define RK3288_SOC_CON2_FLASH0 BIT(7) #define RK3288_SOC_FLASH_SUPPLY_NUM 2 @@ -151,6 +155,25 @@ static int rockchip_iodomain_notify(struct notifier_block *nb, return NOTIFY_OK; } +static void px30_iodomain_init(struct rockchip_iodomain *iod) +{ + int ret; + u32 val; + + /* if no VCCIO0 supply we should leave things alone */ + if (!iod->supplies[PX30_IO_VSEL_VCCIO6_SUPPLY_NUM].reg) + return; + + /* + * set vccio0 iodomain to also use this framework + * instead of a special gpio. + */ + val = PX30_IO_VSEL_VCCIO6_SRC | (PX30_IO_VSEL_VCCIO6_SRC << 16); + ret = regmap_write(iod->grf, PX30_IO_VSEL, val); + if (ret < 0) + dev_warn(iod->dev, "couldn't update vccio0 ctrl\n"); +} + static void rk3288_iodomain_init(struct rockchip_iodomain *iod) { int ret; @@ -227,6 +250,43 @@ static void rk3399_pmu_iodomain_init(struct rockchip_iodomain *iod) dev_warn(iod->dev, "couldn't update pmu io iodomain ctrl\n"); } +static const struct rockchip_iodomain_soc_data soc_data_px30 = { + .grf_offset = 0x180, + .supply_names = { + NULL, + "vccio6", + "vccio1", + "vccio2", + "vccio3", + "vccio4", + "vccio5", + "vccio-oscgpi", + }, + .init = px30_iodomain_init, +}; + +static const struct rockchip_iodomain_soc_data soc_data_px30_pmu = { + .grf_offset = 0x100, + .supply_names = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "pmuio1", + "pmuio2", + }, +}; + /* * On the rk3188 the io-domains are handled by a shared register with the * lower 8 bits being still being continuing drive-strength settings. @@ -381,6 +441,14 @@ static const struct rockchip_iodomain_soc_data soc_data_rv1108_pmu = { static const struct of_device_id rockchip_iodomain_match[] = { { + .compatible = "rockchip,px30-io-voltage-domain", + .data = (void *)&soc_data_px30 + }, + { + .compatible = "rockchip,px30-pmu-io-voltage-domain", + .data = (void *)&soc_data_px30_pmu + }, + { .compatible = "rockchip,rk3188-io-voltage-domain", .data = &soc_data_rk3188 }, diff --git a/drivers/rtc/rtc-proc.c b/drivers/rtc/rtc-proc.c index 31e7e23cc5be..a9dd9218fae2 100644 --- a/drivers/rtc/rtc-proc.c +++ b/drivers/rtc/rtc-proc.c @@ -107,40 +107,11 @@ static int rtc_proc_show(struct seq_file *seq, void *offset) return 0; } -static int rtc_proc_open(struct inode *inode, struct file *file) -{ - int ret; - struct rtc_device *rtc = PDE_DATA(inode); - - if (!try_module_get(rtc->owner)) - return -ENODEV; - - ret = single_open(file, rtc_proc_show, rtc); - if (ret) - module_put(rtc->owner); - return ret; -} - -static int rtc_proc_release(struct inode *inode, struct file *file) -{ - int res = single_release(inode, file); - struct rtc_device *rtc = PDE_DATA(inode); - - module_put(rtc->owner); - return res; -} - -static const struct file_operations rtc_proc_fops = { - .open = rtc_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = rtc_proc_release, -}; - void rtc_proc_add_device(struct rtc_device *rtc) { if (is_rtc_hctosys(rtc)) - proc_create_data("driver/rtc", 0, NULL, &rtc_proc_fops, rtc); + proc_create_single_data("driver/rtc", 0, NULL, rtc_proc_show, + rtc); } void rtc_proc_del_device(struct rtc_device *rtc) diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 04143c08bd6e..73cce3ecb97f 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -2569,14 +2569,11 @@ EXPORT_SYMBOL(dasd_sleep_on_immediatly); * 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) +static int __dasd_cancel_req(struct dasd_ccw_req *cqr) { struct dasd_device *device = cqr->startdev; - unsigned long flags; - int rc; + int rc = 0; - rc = 0; - spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); switch (cqr->status) { case DASD_CQR_QUEUED: /* request was not started - just set to cleared */ @@ -2596,11 +2593,21 @@ int dasd_cancel_req(struct dasd_ccw_req *cqr) default: /* already finished or clear pending - do nothing */ break; } - spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); dasd_schedule_device_bh(device); return rc; } -EXPORT_SYMBOL(dasd_cancel_req); + +int dasd_cancel_req(struct dasd_ccw_req *cqr) +{ + struct dasd_device *device = cqr->startdev; + unsigned long flags; + int rc; + + spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); + rc = __dasd_cancel_req(cqr); + spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); + return rc; +} /* * SECTION: Operations of the dasd_block layer. @@ -3034,7 +3041,8 @@ static blk_status_t do_dasd_request(struct blk_mq_hw_ctx *hctx, cqr->callback_data = req; cqr->status = DASD_CQR_FILLED; cqr->dq = dq; - req->completion_data = cqr; + *((struct dasd_ccw_req **) blk_mq_rq_to_pdu(req)) = cqr; + blk_mq_start_request(req); spin_lock(&block->queue_lock); list_add_tail(&cqr->blocklist, &block->ccw_queue); @@ -3053,19 +3061,20 @@ out: * * Return values: * BLK_EH_RESET_TIMER if the request should be left running - * BLK_EH_NOT_HANDLED if the request is handled or terminated + * BLK_EH_DONE if the request is handled or terminated * by the driver. */ enum blk_eh_timer_return dasd_times_out(struct request *req, bool reserved) { - struct dasd_ccw_req *cqr = req->completion_data; struct dasd_block *block = req->q->queuedata; struct dasd_device *device; + struct dasd_ccw_req *cqr; unsigned long flags; int rc = 0; + cqr = *((struct dasd_ccw_req **) blk_mq_rq_to_pdu(req)); if (!cqr) - return BLK_EH_NOT_HANDLED; + return BLK_EH_DONE; spin_lock_irqsave(&cqr->dq->lock, flags); device = cqr->startdev ? cqr->startdev : block->base; @@ -3082,12 +3091,10 @@ enum blk_eh_timer_return dasd_times_out(struct request *req, bool reserved) cqr->retries = -1; cqr->intrc = -ETIMEDOUT; if (cqr->status >= DASD_CQR_QUEUED) { - spin_unlock(get_ccwdev_lock(device->cdev)); - rc = dasd_cancel_req(cqr); + rc = __dasd_cancel_req(cqr); } else if (cqr->status == DASD_CQR_FILLED || cqr->status == DASD_CQR_NEED_ERP) { cqr->status = DASD_CQR_TERMINATED; - spin_unlock(get_ccwdev_lock(device->cdev)); } else if (cqr->status == DASD_CQR_IN_ERP) { struct dasd_ccw_req *searchcqr, *nextcqr, *tmpcqr; @@ -3102,9 +3109,7 @@ enum blk_eh_timer_return dasd_times_out(struct request *req, bool reserved) searchcqr->retries = -1; searchcqr->intrc = -ETIMEDOUT; if (searchcqr->status >= DASD_CQR_QUEUED) { - spin_unlock(get_ccwdev_lock(device->cdev)); - rc = dasd_cancel_req(searchcqr); - spin_lock(get_ccwdev_lock(device->cdev)); + rc = __dasd_cancel_req(searchcqr); } else if ((searchcqr->status == DASD_CQR_FILLED) || (searchcqr->status == DASD_CQR_NEED_ERP)) { searchcqr->status = DASD_CQR_TERMINATED; @@ -3118,13 +3123,13 @@ enum blk_eh_timer_return dasd_times_out(struct request *req, bool reserved) } break; } - spin_unlock(get_ccwdev_lock(device->cdev)); } + spin_unlock(get_ccwdev_lock(device->cdev)); dasd_schedule_block_bh(block); spin_unlock(&block->queue_lock); spin_unlock_irqrestore(&cqr->dq->lock, flags); - return rc ? BLK_EH_RESET_TIMER : BLK_EH_NOT_HANDLED; + return rc ? BLK_EH_RESET_TIMER : BLK_EH_DONE; } static int dasd_init_hctx(struct blk_mq_hw_ctx *hctx, void *data, @@ -3169,6 +3174,7 @@ static int dasd_alloc_queue(struct dasd_block *block) int rc; block->tag_set.ops = &dasd_mq_ops; + block->tag_set.cmd_size = sizeof(struct dasd_ccw_req *); block->tag_set.nr_hw_queues = DASD_NR_HW_QUEUES; block->tag_set.queue_depth = DASD_MAX_LCU_DEV * DASD_REQ_PER_DEV; block->tag_set.flags = BLK_MQ_F_SHOULD_MERGE; diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index 7bdc6aaa0ba3..2016e0ed5865 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c @@ -18,7 +18,6 @@ #include <linux/fs.h> #include <linux/blkpg.h> #include <linux/slab.h> -#include <asm/compat.h> #include <asm/ccwdev.h> #include <asm/schid.h> #include <asm/cmb.h> diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c index c33788a829c3..5cb80c645489 100644 --- a/drivers/s390/block/dasd_proc.c +++ b/drivers/s390/block/dasd_proc.c @@ -131,19 +131,6 @@ static const struct seq_operations dasd_devices_seq_ops = { .show = dasd_devices_show, }; -static int dasd_devices_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &dasd_devices_seq_ops); -} - -static const struct file_operations dasd_devices_file_ops = { - .owner = THIS_MODULE, - .open = dasd_devices_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - #ifdef CONFIG_DASD_PROFILE static int dasd_stats_all_block_on(void) { @@ -352,10 +339,10 @@ dasd_proc_init(void) dasd_proc_root_entry = proc_mkdir("dasd", NULL); if (!dasd_proc_root_entry) goto out_nodasd; - dasd_devices_entry = proc_create("devices", + dasd_devices_entry = proc_create_seq("devices", S_IFREG | S_IRUGO | S_IWUSR, dasd_proc_root_entry, - &dasd_devices_file_ops); + &dasd_devices_seq_ops); if (!dasd_devices_entry) goto out_nodevices; dasd_statistics_entry = proc_create("statistics", diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile index d049e2d74484..0a4c13e1e76e 100644 --- a/drivers/s390/char/Makefile +++ b/drivers/s390/char/Makefile @@ -54,3 +54,6 @@ obj-$(CONFIG_CRASH_DUMP) += sclp_sdias.o zcore.o hmcdrv-objs := hmcdrv_mod.o hmcdrv_dev.o hmcdrv_ftp.o hmcdrv_cache.o diag_ftp.o sclp_ftp.o obj-$(CONFIG_HMC_DRV) += hmcdrv.o + +chkbss := sclp_early_core.o +include $(srctree)/arch/s390/scripts/Makefile.chkbss diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c index 61822480a2a0..16a4e8528bbc 100644 --- a/drivers/s390/char/fs3270.c +++ b/drivers/s390/char/fs3270.c @@ -19,7 +19,6 @@ #include <linux/slab.h> #include <linux/types.h> -#include <asm/compat.h> #include <asm/ccwdev.h> #include <asm/cio.h> #include <asm/ebcdic.h> diff --git a/drivers/s390/char/sclp_ctl.c b/drivers/s390/char/sclp_ctl.c index a78cea0c3a09..248b5db3eaa8 100644 --- a/drivers/s390/char/sclp_ctl.c +++ b/drivers/s390/char/sclp_ctl.c @@ -14,7 +14,6 @@ #include <linux/init.h> #include <linux/ioctl.h> #include <linux/fs.h> -#include <asm/compat.h> #include <asm/sclp_ctl.h> #include <asm/sclp.h> diff --git a/drivers/s390/char/tape_proc.c b/drivers/s390/char/tape_proc.c index faae30476f4b..32a14ee31c6b 100644 --- a/drivers/s390/char/tape_proc.c +++ b/drivers/s390/char/tape_proc.c @@ -105,29 +105,14 @@ static const struct seq_operations tape_proc_seq = { .show = tape_proc_show, }; -static int tape_proc_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &tape_proc_seq); -} - -static const struct file_operations tape_proc_ops = -{ - .owner = THIS_MODULE, - .open = tape_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - /* * Initialize procfs stuff on startup */ void tape_proc_init(void) { - tape_proc_devices = - proc_create("tapedevices", S_IFREG | S_IRUGO | S_IWUSR, NULL, - &tape_proc_ops); + tape_proc_devices = proc_create_seq("tapedevices", + S_IFREG | S_IRUGO | S_IWUSR, NULL, &tape_proc_seq); if (tape_proc_devices == NULL) { return; } diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c index 17e411c57576..948ce82a7725 100644 --- a/drivers/s390/char/vmcp.c +++ b/drivers/s390/char/vmcp.c @@ -23,7 +23,6 @@ #include <linux/mutex.h> #include <linux/cma.h> #include <linux/mm.h> -#include <asm/compat.h> #include <asm/cpcmd.h> #include <asm/debug.h> #include <asm/vmcp.h> diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 5535312602af..db9c854088bc 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -561,6 +561,12 @@ static struct bus_type ccwgroup_bus_type = { .pm = &ccwgroup_pm_ops, }; +bool dev_is_ccwgroup(struct device *dev) +{ + return dev->bus == &ccwgroup_bus_type; +} +EXPORT_SYMBOL(dev_is_ccwgroup); + /** * ccwgroup_driver_register() - register a ccw group driver * @cdriver: driver to be registered diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c index 0015729d917d..8d9f36625ba5 100644 --- a/drivers/s390/cio/chsc_sch.c +++ b/drivers/s390/cio/chsc_sch.c @@ -16,7 +16,6 @@ #include <linux/miscdevice.h> #include <linux/kernel_stat.h> -#include <asm/compat.h> #include <asm/cio.h> #include <asm/chsc.h> #include <asm/isc.h> diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index aecfebb74157..4435ae0b3027 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c @@ -473,6 +473,36 @@ struct channel_path_desc_fmt0 *ccw_device_get_chp_desc(struct ccw_device *cdev, } /** + * ccw_device_get_util_str() - return newly allocated utility strings + * @cdev: device to obtain the utility strings for + * @chp_idx: index of the channel path + * + * On success return a newly allocated copy of the utility strings + * associated with the given channel path. Return %NULL on error. + */ +u8 *ccw_device_get_util_str(struct ccw_device *cdev, int chp_idx) +{ + struct subchannel *sch = to_subchannel(cdev->dev.parent); + struct channel_path *chp; + struct chp_id chpid; + u8 *util_str; + + chp_id_init(&chpid); + chpid.id = sch->schib.pmcw.chpid[chp_idx]; + chp = chpid_to_chp(chpid); + + util_str = kmalloc(sizeof(chp->desc_fmt3.util_str), GFP_KERNEL); + if (!util_str) + return NULL; + + mutex_lock(&chp->lock); + memcpy(util_str, chp->desc_fmt3.util_str, sizeof(chp->desc_fmt3.util_str)); + mutex_unlock(&chp->lock); + + return util_str; +} + +/** * ccw_device_get_id() - obtain a ccw device id * @cdev: device to obtain the id for * @dev_id: where to fill in the values @@ -682,3 +712,4 @@ EXPORT_SYMBOL(ccw_device_start_key); EXPORT_SYMBOL(ccw_device_get_ciw); EXPORT_SYMBOL(ccw_device_get_path_mask); EXPORT_SYMBOL_GPL(ccw_device_get_chp_desc); +EXPORT_SYMBOL_GPL(ccw_device_get_util_str); diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h index 02184cf35834..6a273c5ebca5 100644 --- a/drivers/s390/crypto/ap_bus.h +++ b/drivers/s390/crypto/ap_bus.h @@ -198,11 +198,18 @@ struct ap_message { */ static inline void ap_init_message(struct ap_message *ap_msg) { - ap_msg->psmid = 0; - ap_msg->length = 0; - ap_msg->rc = 0; - ap_msg->special = 0; - ap_msg->receive = NULL; + memset(ap_msg, 0, sizeof(*ap_msg)); +} + +/** + * ap_release_message() - Release ap_message. + * Releases all memory used internal within the ap_message struct + * Currently this is the message and private field. + */ +static inline void ap_release_message(struct ap_message *ap_msg) +{ + kzfree(ap_msg->message); + kzfree(ap_msg->private); } #define for_each_ap_card(_ac) \ diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 5efd84862ccb..febcdb5135bf 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -371,6 +371,7 @@ long zcrypt_send_cprb(struct ica_xcRB *xcRB) trace_s390_zcrypt_req(xcRB, TB_ZSECSENDCPRB); + ap_init_message(&ap_msg); rc = get_cprb_fc(xcRB, &ap_msg, &func_code, &domain); if (rc) goto out; @@ -425,6 +426,7 @@ long zcrypt_send_cprb(struct ica_xcRB *xcRB) spin_unlock(&zcrypt_list_lock); out: + ap_release_message(&ap_msg); trace_s390_zcrypt_rep(xcRB, func_code, rc, AP_QID_CARD(qid), AP_QID_QUEUE(qid)); return rc; @@ -468,6 +470,8 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb) trace_s390_zcrypt_req(xcrb, TP_ZSENDEP11CPRB); + ap_init_message(&ap_msg); + target_num = (unsigned short) xcrb->targets_num; /* empty list indicates autoselect (all available targets) */ @@ -485,7 +489,7 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb) if (copy_from_user(targets, uptr, target_num * sizeof(*targets))) { rc = -EFAULT; - goto out; + goto out_free; } } @@ -542,6 +546,7 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb) out_free: kfree(targets); out: + ap_release_message(&ap_msg); trace_s390_zcrypt_rep(xcrb, func_code, rc, AP_QID_CARD(qid), AP_QID_QUEUE(qid)); return rc; @@ -559,6 +564,7 @@ static long zcrypt_rng(char *buffer) trace_s390_zcrypt_req(buffer, TP_HWRNGCPRB); + ap_init_message(&ap_msg); rc = get_rng_fc(&ap_msg, &func_code, &domain); if (rc) goto out; @@ -589,8 +595,10 @@ static long zcrypt_rng(char *buffer) pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, weight); spin_unlock(&zcrypt_list_lock); - if (!pref_zq) - return -ENODEV; + if (!pref_zq) { + rc = -ENODEV; + goto out; + } qid = pref_zq->queue->qid; rc = pref_zq->ops->rng(pref_zq, buffer, &ap_msg); @@ -600,6 +608,7 @@ static long zcrypt_rng(char *buffer) spin_unlock(&zcrypt_list_lock); out: + ap_release_message(&ap_msg); trace_s390_zcrypt_rep(buffer, func_code, rc, AP_QID_CARD(qid), AP_QID_QUEUE(qid)); return rc; diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c index f54bef4a928e..97d4bacbc442 100644 --- a/drivers/s390/crypto/zcrypt_msgtype6.c +++ b/drivers/s390/crypto/zcrypt_msgtype6.c @@ -1084,6 +1084,13 @@ out_free: return rc; } +/** + * Fetch function code from cprb. + * Extracting the fc requires to copy the cprb from userspace. + * So this function allocates memory and needs an ap_msg prepared + * by the caller with ap_init_message(). Also the caller has to + * make sure ap_release_message() is always called even on failure. + */ unsigned int get_cprb_fc(struct ica_xcRB *xcRB, struct ap_message *ap_msg, unsigned int *func_code, unsigned short **dom) @@ -1091,9 +1098,7 @@ unsigned int get_cprb_fc(struct ica_xcRB *xcRB, struct response_type resp_type = { .type = PCIXCC_RESPONSE_TYPE_XCRB, }; - int rc; - ap_init_message(ap_msg); ap_msg->message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL); if (!ap_msg->message) return -ENOMEM; @@ -1101,17 +1106,10 @@ unsigned int get_cprb_fc(struct ica_xcRB *xcRB, ap_msg->psmid = (((unsigned long long) current->pid) << 32) + atomic_inc_return(&zcrypt_step); ap_msg->private = kmalloc(sizeof(resp_type), GFP_KERNEL); - if (!ap_msg->private) { - kzfree(ap_msg->message); + if (!ap_msg->private) return -ENOMEM; - } memcpy(ap_msg->private, &resp_type, sizeof(resp_type)); - rc = XCRB_msg_to_type6CPRB_msgX(ap_msg, xcRB, func_code, dom); - if (rc) { - kzfree(ap_msg->message); - kzfree(ap_msg->private); - } - return rc; + return XCRB_msg_to_type6CPRB_msgX(ap_msg, xcRB, func_code, dom); } /** @@ -1139,11 +1137,16 @@ static long zcrypt_msgtype6_send_cprb(struct zcrypt_queue *zq, /* Signal pending. */ ap_cancel_message(zq->queue, ap_msg); - kzfree(ap_msg->message); - kzfree(ap_msg->private); return rc; } +/** + * Fetch function code from ep11 cprb. + * Extracting the fc requires to copy the ep11 cprb from userspace. + * So this function allocates memory and needs an ap_msg prepared + * by the caller with ap_init_message(). Also the caller has to + * make sure ap_release_message() is always called even on failure. + */ unsigned int get_ep11cprb_fc(struct ep11_urb *xcrb, struct ap_message *ap_msg, unsigned int *func_code) @@ -1151,9 +1154,7 @@ unsigned int get_ep11cprb_fc(struct ep11_urb *xcrb, struct response_type resp_type = { .type = PCIXCC_RESPONSE_TYPE_EP11, }; - int rc; - ap_init_message(ap_msg); ap_msg->message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL); if (!ap_msg->message) return -ENOMEM; @@ -1161,17 +1162,10 @@ unsigned int get_ep11cprb_fc(struct ep11_urb *xcrb, ap_msg->psmid = (((unsigned long long) current->pid) << 32) + atomic_inc_return(&zcrypt_step); ap_msg->private = kmalloc(sizeof(resp_type), GFP_KERNEL); - if (!ap_msg->private) { - kzfree(ap_msg->message); + if (!ap_msg->private) return -ENOMEM; - } memcpy(ap_msg->private, &resp_type, sizeof(resp_type)); - rc = xcrb_msg_to_type6_ep11cprb_msgx(ap_msg, xcrb, func_code); - if (rc) { - kzfree(ap_msg->message); - kzfree(ap_msg->private); - } - return rc; + return xcrb_msg_to_type6_ep11cprb_msgx(ap_msg, xcrb, func_code); } /** @@ -1246,8 +1240,6 @@ static long zcrypt_msgtype6_send_ep11_cprb(struct zcrypt_queue *zq, /* Signal pending. */ ap_cancel_message(zq->queue, ap_msg); - kzfree(ap_msg->message); - kzfree(ap_msg->private); return rc; } @@ -1258,7 +1250,6 @@ unsigned int get_rng_fc(struct ap_message *ap_msg, int *func_code, .type = PCIXCC_RESPONSE_TYPE_XCRB, }; - ap_init_message(ap_msg); ap_msg->message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL); if (!ap_msg->message) return -ENOMEM; @@ -1266,10 +1257,8 @@ unsigned int get_rng_fc(struct ap_message *ap_msg, int *func_code, ap_msg->psmid = (((unsigned long long) current->pid) << 32) + atomic_inc_return(&zcrypt_step); ap_msg->private = kmalloc(sizeof(resp_type), GFP_KERNEL); - if (!ap_msg->private) { - kzfree(ap_msg->message); + if (!ap_msg->private) return -ENOMEM; - } memcpy(ap_msg->private, &resp_type, sizeof(resp_type)); rng_type6CPRB_msgX(ap_msg, ZCRYPT_RNG_BUFFER_SIZE, domain); @@ -1313,8 +1302,6 @@ static long zcrypt_msgtype6_rng(struct zcrypt_queue *zq, /* Signal pending. */ ap_cancel_message(zq->queue, ap_msg); - kzfree(ap_msg->message); - kzfree(ap_msg->private); return rc; } diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index dffd820731f2..f5a0d894d9ad 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -10,6 +10,7 @@ #define KMSG_COMPONENT "qeth" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +#include <linux/compat.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/string.h> @@ -32,7 +33,6 @@ #include <asm/chpid.h> #include <asm/io.h> #include <asm/sysinfo.h> -#include <asm/compat.h> #include <asm/diag.h> #include <asm/cio.h> #include <asm/ccwdev.h> diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index a8b831000b2d..18c4f933e8b9 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -4,7 +4,7 @@ * * Debug traces for zfcp. * - * Copyright IBM Corp. 2002, 2017 + * Copyright IBM Corp. 2002, 2018 */ #define KMSG_COMPONENT "zfcp" @@ -308,6 +308,27 @@ void zfcp_dbf_rec_trig(char *tag, struct zfcp_adapter *adapter, spin_unlock_irqrestore(&dbf->rec_lock, flags); } +/** + * zfcp_dbf_rec_trig_lock - trace event related to triggered recovery with lock + * @tag: identifier for event + * @adapter: adapter on which the erp_action should run + * @port: remote port involved in the erp_action + * @sdev: scsi device involved in the erp_action + * @want: wanted erp_action + * @need: required erp_action + * + * The adapter->erp_lock must not be held. + */ +void zfcp_dbf_rec_trig_lock(char *tag, struct zfcp_adapter *adapter, + struct zfcp_port *port, struct scsi_device *sdev, + u8 want, u8 need) +{ + unsigned long flags; + + read_lock_irqsave(&adapter->erp_lock, flags); + zfcp_dbf_rec_trig(tag, adapter, port, sdev, want, need); + read_unlock_irqrestore(&adapter->erp_lock, flags); +} /** * zfcp_dbf_rec_run_lvl - trace event related to running recovery diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index bf8ea4df2bb8..e5eed8aac0ce 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -4,7 +4,7 @@ * * External function declarations. * - * Copyright IBM Corp. 2002, 2016 + * Copyright IBM Corp. 2002, 2018 */ #ifndef ZFCP_EXT_H @@ -35,6 +35,9 @@ extern int zfcp_dbf_adapter_register(struct zfcp_adapter *); extern void zfcp_dbf_adapter_unregister(struct zfcp_adapter *); extern void zfcp_dbf_rec_trig(char *, struct zfcp_adapter *, struct zfcp_port *, struct scsi_device *, u8, u8); +extern void zfcp_dbf_rec_trig_lock(char *tag, struct zfcp_adapter *adapter, + struct zfcp_port *port, + struct scsi_device *sdev, u8 want, u8 need); extern void zfcp_dbf_rec_run(char *, struct zfcp_erp_action *); extern void zfcp_dbf_rec_run_lvl(int level, char *tag, struct zfcp_erp_action *erp); diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 4d2ba5682493..22f9562f415c 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -4,7 +4,7 @@ * * Interface to Linux SCSI midlayer. * - * Copyright IBM Corp. 2002, 2017 + * Copyright IBM Corp. 2002, 2018 */ #define KMSG_COMPONENT "zfcp" @@ -618,9 +618,9 @@ static void zfcp_scsi_rport_register(struct zfcp_port *port) ids.port_id = port->d_id; ids.roles = FC_RPORT_ROLE_FCP_TARGET; - zfcp_dbf_rec_trig("scpaddy", port->adapter, port, NULL, - ZFCP_PSEUDO_ERP_ACTION_RPORT_ADD, - ZFCP_PSEUDO_ERP_ACTION_RPORT_ADD); + zfcp_dbf_rec_trig_lock("scpaddy", port->adapter, port, NULL, + ZFCP_PSEUDO_ERP_ACTION_RPORT_ADD, + ZFCP_PSEUDO_ERP_ACTION_RPORT_ADD); rport = fc_remote_port_add(port->adapter->scsi_host, 0, &ids); if (!rport) { dev_err(&port->adapter->ccw_device->dev, @@ -642,9 +642,9 @@ static void zfcp_scsi_rport_block(struct zfcp_port *port) struct fc_rport *rport = port->rport; if (rport) { - zfcp_dbf_rec_trig("scpdely", port->adapter, port, NULL, - ZFCP_PSEUDO_ERP_ACTION_RPORT_DEL, - ZFCP_PSEUDO_ERP_ACTION_RPORT_DEL); + zfcp_dbf_rec_trig_lock("scpdely", port->adapter, port, NULL, + ZFCP_PSEUDO_ERP_ACTION_RPORT_DEL, + ZFCP_PSEUDO_ERP_ACTION_RPORT_DEL); fc_remote_port_delete(rport); port->rport = NULL; } diff --git a/drivers/sbus/char/Kconfig b/drivers/sbus/char/Kconfig index bf3c5f735614..89edd13fd572 100644 --- a/drivers/sbus/char/Kconfig +++ b/drivers/sbus/char/Kconfig @@ -28,13 +28,6 @@ config TADPOLE_TS102_UCTRL events, and can also notice the attachment/detachment of external monitors and mice. -config SUN_JSFLASH - tristate "JavaStation OS Flash SIMM" - depends on SPARC32 - help - If you say Y here, you will be able to boot from your JavaStation's - Flash memory. - config BBC_I2C tristate "UltraSPARC-III bootbus i2c controller driver" depends on PCI && SPARC64 diff --git a/drivers/sbus/char/Makefile b/drivers/sbus/char/Makefile index 8c48ed96683f..44347c918f6b 100644 --- a/drivers/sbus/char/Makefile +++ b/drivers/sbus/char/Makefile @@ -15,6 +15,5 @@ obj-$(CONFIG_DISPLAY7SEG) += display7seg.o obj-$(CONFIG_OBP_FLASH) += flash.o obj-$(CONFIG_SUN_OPENPROMIO) += openprom.o obj-$(CONFIG_TADPOLE_TS102_UCTRL) += uctrl.o -obj-$(CONFIG_SUN_JSFLASH) += jsflash.o obj-$(CONFIG_BBC_I2C) += bbc.o obj-$(CONFIG_ORACLE_DAX) += oradax.o diff --git a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c deleted file mode 100644 index 14f377ac1280..000000000000 --- a/drivers/sbus/char/jsflash.c +++ /dev/null @@ -1,658 +0,0 @@ -/* - * drivers/sbus/char/jsflash.c - * - * Copyright (C) 1991, 1992 Linus Torvalds (drivers/char/mem.c) - * Copyright (C) 1997 Eddie C. Dost (drivers/sbus/char/flash.c) - * Copyright (C) 1997-2000 Pavel Machek <pavel@ucw.cz> (drivers/block/nbd.c) - * Copyright (C) 1999-2000 Pete Zaitcev - * - * This driver is used to program OS into a Flash SIMM on - * Krups and Espresso platforms. - * - * TODO: do not allow erase/programming if file systems are mounted. - * TODO: Erase/program both banks of a 8MB SIMM. - * - * It is anticipated that programming an OS Flash will be a routine - * procedure. In the same time it is exceedingly dangerous because - * a user can program its OBP flash with OS image and effectively - * kill the machine. - * - * This driver uses an interface different from Eddie's flash.c - * as a silly safeguard. - * - * XXX The flash.c manipulates page caching characteristics in a certain - * dubious way; also it assumes that remap_pfn_range() can remap - * PCI bus locations, which may be false. ioremap() must be used - * instead. We should discuss this. - */ - -#include <linux/module.h> -#include <linux/mutex.h> -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/miscdevice.h> -#include <linux/fcntl.h> -#include <linux/poll.h> -#include <linux/init.h> -#include <linux/string.h> -#include <linux/genhd.h> -#include <linux/blkdev.h> -#include <linux/uaccess.h> -#include <asm/pgtable.h> -#include <asm/io.h> -#include <asm/pcic.h> -#include <asm/oplib.h> - -#include <asm/jsflash.h> /* ioctl arguments. <linux/> ?? */ -#define JSFIDSZ (sizeof(struct jsflash_ident_arg)) -#define JSFPRGSZ (sizeof(struct jsflash_program_arg)) - -/* - * Our device numbers have no business in system headers. - * The only thing a user knows is the device name /dev/jsflash. - * - * Block devices are laid out like this: - * minor+0 - Bootstrap, for 8MB SIMM 0x20400000[0x800000] - * minor+1 - Filesystem to mount, normally 0x20400400[0x7ffc00] - * minor+2 - Whole flash area for any case... 0x20000000[0x01000000] - * Total 3 minors per flash device. - * - * It is easier to have static size vectors, so we define - * a total minor range JSF_MAX, which must cover all minors. - */ -/* character device */ -#define JSF_MINOR 178 /* 178 is registered with hpa */ -/* block device */ -#define JSF_MAX 3 /* 3 minors wasted total so far. */ -#define JSF_NPART 3 /* 3 minors per flash device */ -#define JSF_PART_BITS 2 /* 2 bits of minors to cover JSF_NPART */ -#define JSF_PART_MASK 0x3 /* 2 bits mask */ - -static DEFINE_MUTEX(jsf_mutex); - -/* - * Access functions. - * We could ioremap(), but it's easier this way. - */ -static unsigned int jsf_inl(unsigned long addr) -{ - unsigned long retval; - - __asm__ __volatile__("lda [%1] %2, %0\n\t" : - "=r" (retval) : - "r" (addr), "i" (ASI_M_BYPASS)); - return retval; -} - -static void jsf_outl(unsigned long addr, __u32 data) -{ - - __asm__ __volatile__("sta %0, [%1] %2\n\t" : : - "r" (data), "r" (addr), "i" (ASI_M_BYPASS) : - "memory"); -} - -/* - * soft carrier - */ - -struct jsfd_part { - unsigned long dbase; - unsigned long dsize; -}; - -struct jsflash { - unsigned long base; - unsigned long size; - unsigned long busy; /* In use? */ - struct jsflash_ident_arg id; - /* int mbase; */ /* Minor base, typically zero */ - struct jsfd_part dv[JSF_NPART]; -}; - -/* - * We do not map normal memory or obio as a safety precaution. - * But offsets are real, for ease of userland programming. - */ -#define JSF_BASE_TOP 0x30000000 -#define JSF_BASE_ALL 0x20000000 - -#define JSF_BASE_JK 0x20400000 - -/* - */ -static struct gendisk *jsfd_disk[JSF_MAX]; - -/* - * Let's pretend we may have several of these... - */ -static struct jsflash jsf0; - -/* - * Wait for AMD to finish its embedded algorithm. - * We use the Toggle bit DQ6 (0x40) because it does not - * depend on the data value as /DATA bit DQ7 does. - * - * XXX Do we need any timeout here? So far it never hanged, beware broken hw. - */ -static void jsf_wait(unsigned long p) { - unsigned int x1, x2; - - for (;;) { - x1 = jsf_inl(p); - x2 = jsf_inl(p); - if ((x1 & 0x40404040) == (x2 & 0x40404040)) return; - } -} - -/* - * Programming will only work if Flash is clean, - * we leave it to the programmer application. - * - * AMD must be programmed one byte at a time; - * thus, Simple Tech SIMM must be written 4 bytes at a time. - * - * Write waits for the chip to become ready after the write - * was finished. This is done so that application would read - * consistent data after the write is done. - */ -static void jsf_write4(unsigned long fa, u32 data) { - - jsf_outl(fa, 0xAAAAAAAA); /* Unlock 1 Write 1 */ - jsf_outl(fa, 0x55555555); /* Unlock 1 Write 2 */ - jsf_outl(fa, 0xA0A0A0A0); /* Byte Program */ - jsf_outl(fa, data); - - jsf_wait(fa); -} - -/* - */ -static void jsfd_read(char *buf, unsigned long p, size_t togo) { - union byte4 { - char s[4]; - unsigned int n; - } b; - - while (togo >= 4) { - togo -= 4; - b.n = jsf_inl(p); - memcpy(buf, b.s, 4); - p += 4; - buf += 4; - } -} - -static int jsfd_queue; - -static struct request *jsfd_next_request(void) -{ - struct request_queue *q; - struct request *rq; - int old_pos = jsfd_queue; - - do { - q = jsfd_disk[jsfd_queue]->queue; - if (++jsfd_queue == JSF_MAX) - jsfd_queue = 0; - if (q) { - rq = blk_fetch_request(q); - if (rq) - return rq; - } - } while (jsfd_queue != old_pos); - - return NULL; -} - -static void jsfd_request(void) -{ - struct request *req; - - req = jsfd_next_request(); - while (req) { - struct jsfd_part *jdp = req->rq_disk->private_data; - unsigned long offset = blk_rq_pos(req) << 9; - size_t len = blk_rq_cur_bytes(req); - blk_status_t err = BLK_STS_IOERR; - - if ((offset + len) > jdp->dsize) - goto end; - - if (rq_data_dir(req) != READ) { - printk(KERN_ERR "jsfd: write\n"); - goto end; - } - - if ((jdp->dbase & 0xff000000) != 0x20000000) { - printk(KERN_ERR "jsfd: bad base %x\n", (int)jdp->dbase); - goto end; - } - - jsfd_read(bio_data(req->bio), jdp->dbase + offset, len); - err = BLK_STS_OK; - end: - if (!__blk_end_request_cur(req, err)) - req = jsfd_next_request(); - } -} - -static void jsfd_do_request(struct request_queue *q) -{ - jsfd_request(); -} - -/* - * The memory devices use the full 32/64 bits of the offset, and so we cannot - * check against negative addresses: they are ok. The return value is weird, - * though, in that case (0). - * - * also note that seeking relative to the "end of file" isn't supported: - * it has no meaning, so it returns -EINVAL. - */ -static loff_t jsf_lseek(struct file * file, loff_t offset, int orig) -{ - loff_t ret; - - mutex_lock(&jsf_mutex); - switch (orig) { - case 0: - file->f_pos = offset; - ret = file->f_pos; - break; - case 1: - file->f_pos += offset; - ret = file->f_pos; - break; - default: - ret = -EINVAL; - } - mutex_unlock(&jsf_mutex); - return ret; -} - -/* - * OS SIMM Cannot be read in other size but a 32bits word. - */ -static ssize_t jsf_read(struct file * file, char __user * buf, - size_t togo, loff_t *ppos) -{ - unsigned long p = *ppos; - char __user *tmp = buf; - - union byte4 { - char s[4]; - unsigned int n; - } b; - - if (p < JSF_BASE_ALL || p >= JSF_BASE_TOP) { - return 0; - } - - if ((p + togo) < p /* wrap */ - || (p + togo) >= JSF_BASE_TOP) { - togo = JSF_BASE_TOP - p; - } - - if (p < JSF_BASE_ALL && togo != 0) { -#if 0 /* __bzero XXX */ - size_t x = JSF_BASE_ALL - p; - if (x > togo) x = togo; - clear_user(tmp, x); - tmp += x; - p += x; - togo -= x; -#else - /* - * Implementation of clear_user() calls __bzero - * without regard to modversions, - * so we cannot build a module. - */ - return 0; -#endif - } - - while (togo >= 4) { - togo -= 4; - b.n = jsf_inl(p); - if (copy_to_user(tmp, b.s, 4)) - return -EFAULT; - tmp += 4; - p += 4; - } - - /* - * XXX Small togo may remain if 1 byte is ordered. - * It would be nice if we did a word size read and unpacked it. - */ - - *ppos = p; - return tmp-buf; -} - -static ssize_t jsf_write(struct file * file, const char __user * buf, - size_t count, loff_t *ppos) -{ - return -ENOSPC; -} - -/* - */ -static int jsf_ioctl_erase(unsigned long arg) -{ - unsigned long p; - - /* p = jsf0.base; hits wrong bank */ - p = 0x20400000; - - jsf_outl(p, 0xAAAAAAAA); /* Unlock 1 Write 1 */ - jsf_outl(p, 0x55555555); /* Unlock 1 Write 2 */ - jsf_outl(p, 0x80808080); /* Erase setup */ - jsf_outl(p, 0xAAAAAAAA); /* Unlock 2 Write 1 */ - jsf_outl(p, 0x55555555); /* Unlock 2 Write 2 */ - jsf_outl(p, 0x10101010); /* Chip erase */ - -#if 0 - /* - * This code is ok, except that counter based timeout - * has no place in this world. Let's just drop timeouts... - */ - { - int i; - __u32 x; - for (i = 0; i < 1000000; i++) { - x = jsf_inl(p); - if ((x & 0x80808080) == 0x80808080) break; - } - if ((x & 0x80808080) != 0x80808080) { - printk("jsf0: erase timeout with 0x%08x\n", x); - } else { - printk("jsf0: erase done with 0x%08x\n", x); - } - } -#else - jsf_wait(p); -#endif - - return 0; -} - -/* - * Program a block of flash. - * Very simple because we can do it byte by byte anyway. - */ -static int jsf_ioctl_program(void __user *arg) -{ - struct jsflash_program_arg abuf; - char __user *uptr; - unsigned long p; - unsigned int togo; - union { - unsigned int n; - char s[4]; - } b; - - if (copy_from_user(&abuf, arg, JSFPRGSZ)) - return -EFAULT; - p = abuf.off; - togo = abuf.size; - if ((togo & 3) || (p & 3)) return -EINVAL; - - uptr = (char __user *) (unsigned long) abuf.data; - while (togo != 0) { - togo -= 4; - if (copy_from_user(&b.s[0], uptr, 4)) - return -EFAULT; - jsf_write4(p, b.n); - p += 4; - uptr += 4; - } - - return 0; -} - -static long jsf_ioctl(struct file *f, unsigned int cmd, unsigned long arg) -{ - mutex_lock(&jsf_mutex); - int error = -ENOTTY; - void __user *argp = (void __user *)arg; - - if (!capable(CAP_SYS_ADMIN)) { - mutex_unlock(&jsf_mutex); - return -EPERM; - } - switch (cmd) { - case JSFLASH_IDENT: - if (copy_to_user(argp, &jsf0.id, JSFIDSZ)) { - mutex_unlock(&jsf_mutex); - return -EFAULT; - } - break; - case JSFLASH_ERASE: - error = jsf_ioctl_erase(arg); - break; - case JSFLASH_PROGRAM: - error = jsf_ioctl_program(argp); - break; - } - - mutex_unlock(&jsf_mutex); - return error; -} - -static int jsf_mmap(struct file * file, struct vm_area_struct * vma) -{ - return -ENXIO; -} - -static int jsf_open(struct inode * inode, struct file * filp) -{ - mutex_lock(&jsf_mutex); - if (jsf0.base == 0) { - mutex_unlock(&jsf_mutex); - return -ENXIO; - } - if (test_and_set_bit(0, (void *)&jsf0.busy) != 0) { - mutex_unlock(&jsf_mutex); - return -EBUSY; - } - - mutex_unlock(&jsf_mutex); - return 0; /* XXX What security? */ -} - -static int jsf_release(struct inode *inode, struct file *file) -{ - jsf0.busy = 0; - return 0; -} - -static const struct file_operations jsf_fops = { - .owner = THIS_MODULE, - .llseek = jsf_lseek, - .read = jsf_read, - .write = jsf_write, - .unlocked_ioctl = jsf_ioctl, - .mmap = jsf_mmap, - .open = jsf_open, - .release = jsf_release, -}; - -static struct miscdevice jsf_dev = { JSF_MINOR, "jsflash", &jsf_fops }; - -static const struct block_device_operations jsfd_fops = { - .owner = THIS_MODULE, -}; - -static int jsflash_init(void) -{ - int rc; - struct jsflash *jsf; - phandle node; - char banner[128]; - struct linux_prom_registers reg0; - - node = prom_getchild(prom_root_node); - node = prom_searchsiblings(node, "flash-memory"); - if (node != 0 && (s32)node != -1) { - if (prom_getproperty(node, "reg", - (char *)®0, sizeof(reg0)) == -1) { - printk("jsflash: no \"reg\" property\n"); - return -ENXIO; - } - if (reg0.which_io != 0) { - printk("jsflash: bus number nonzero: 0x%x:%x\n", - reg0.which_io, reg0.phys_addr); - return -ENXIO; - } - /* - * Flash may be somewhere else, for instance on Ebus. - * So, don't do the following check for IIep flash space. - */ -#if 0 - if ((reg0.phys_addr >> 24) != 0x20) { - printk("jsflash: suspicious address: 0x%x:%x\n", - reg0.which_io, reg0.phys_addr); - return -ENXIO; - } -#endif - if ((int)reg0.reg_size <= 0) { - printk("jsflash: bad size 0x%x\n", (int)reg0.reg_size); - return -ENXIO; - } - } else { - /* XXX Remove this code once PROLL ID12 got widespread */ - printk("jsflash: no /flash-memory node, use PROLL >= 12\n"); - prom_getproperty(prom_root_node, "banner-name", banner, 128); - if (strcmp (banner, "JavaStation-NC") != 0 && - strcmp (banner, "JavaStation-E") != 0) { - return -ENXIO; - } - reg0.which_io = 0; - reg0.phys_addr = 0x20400000; - reg0.reg_size = 0x00800000; - } - - /* Let us be really paranoid for modifications to probing code. */ - if (sparc_cpu_model != sun4m) { - /* We must be on sun4m because we use MMU Bypass ASI. */ - return -ENXIO; - } - - if (jsf0.base == 0) { - jsf = &jsf0; - - jsf->base = reg0.phys_addr; - jsf->size = reg0.reg_size; - - /* XXX Redo the userland interface. */ - jsf->id.off = JSF_BASE_ALL; - jsf->id.size = 0x01000000; /* 16M - all segments */ - strcpy(jsf->id.name, "Krups_all"); - - jsf->dv[0].dbase = jsf->base; - jsf->dv[0].dsize = jsf->size; - jsf->dv[1].dbase = jsf->base + 1024; - jsf->dv[1].dsize = jsf->size - 1024; - jsf->dv[2].dbase = JSF_BASE_ALL; - jsf->dv[2].dsize = 0x01000000; - - printk("Espresso Flash @0x%lx [%d MB]\n", jsf->base, - (int) (jsf->size / (1024*1024))); - } - - if ((rc = misc_register(&jsf_dev)) != 0) { - printk(KERN_ERR "jsf: unable to get misc minor %d\n", - JSF_MINOR); - jsf0.base = 0; - return rc; - } - - return 0; -} - -static int jsfd_init(void) -{ - static DEFINE_SPINLOCK(lock); - struct jsflash *jsf; - struct jsfd_part *jdp; - int err; - int i; - - if (jsf0.base == 0) - return -ENXIO; - - err = -ENOMEM; - for (i = 0; i < JSF_MAX; i++) { - struct gendisk *disk = alloc_disk(1); - if (!disk) - goto out; - disk->queue = blk_init_queue(jsfd_do_request, &lock); - if (!disk->queue) { - put_disk(disk); - goto out; - } - blk_queue_bounce_limit(disk->queue, BLK_BOUNCE_HIGH); - jsfd_disk[i] = disk; - } - - if (register_blkdev(JSFD_MAJOR, "jsfd")) { - err = -EIO; - goto out; - } - - for (i = 0; i < JSF_MAX; i++) { - struct gendisk *disk = jsfd_disk[i]; - if ((i & JSF_PART_MASK) >= JSF_NPART) continue; - jsf = &jsf0; /* actually, &jsfv[i >> JSF_PART_BITS] */ - jdp = &jsf->dv[i&JSF_PART_MASK]; - - disk->major = JSFD_MAJOR; - disk->first_minor = i; - sprintf(disk->disk_name, "jsfd%d", i); - disk->fops = &jsfd_fops; - set_capacity(disk, jdp->dsize >> 9); - disk->private_data = jdp; - add_disk(disk); - set_disk_ro(disk, 1); - } - return 0; -out: - while (i--) - put_disk(jsfd_disk[i]); - return err; -} - -MODULE_LICENSE("GPL"); - -static int __init jsflash_init_module(void) { - int rc; - - if ((rc = jsflash_init()) == 0) { - jsfd_init(); - return 0; - } - return rc; -} - -static void __exit jsflash_cleanup_module(void) -{ - int i; - - for (i = 0; i < JSF_MAX; i++) { - if ((i & JSF_PART_MASK) >= JSF_NPART) continue; - del_gendisk(jsfd_disk[i]); - blk_cleanup_queue(jsfd_disk[i]->queue); - put_disk(jsfd_disk[i]); - } - if (jsf0.busy) - printk("jsf0: cleaning busy unit\n"); - jsf0.base = 0; - jsf0.busy = 0; - - misc_deregister(&jsf_dev); - unregister_blkdev(JSFD_MAJOR, "jsfd"); -} - -module_init(jsflash_init_module); -module_exit(jsflash_cleanup_module); diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index e29f9b8fd66d..56c940394729 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -182,7 +182,7 @@ zalon7xx-objs := zalon.o ncr53c8xx.o NCR_Q720_mod-objs := NCR_Q720.o ncr53c8xx.o # Files generated that shall be removed upon make clean -clean-files := 53c700_d.h 53c700_u.h +clean-files := 53c700_d.h 53c700_u.h scsi_devinfo_tbl.c $(obj)/53c700.o $(MODVERDIR)/$(obj)/53c700.ver: $(obj)/53c700_d.h diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index c35f05c4c6bb..85604795d8ee 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -3882,7 +3882,7 @@ static enum blk_eh_timer_return gdth_timed_out(struct scsi_cmnd *scp) struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp); u8 b, t; unsigned long flags; - enum blk_eh_timer_return retval = BLK_EH_NOT_HANDLED; + enum blk_eh_timer_return retval = BLK_EH_DONE; TRACE(("%s() cmd 0x%x\n", scp->cmnd[0], __func__)); b = scp->device->channel; diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 15a2fef51e38..71bdc0b52cf9 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1963,7 +1963,7 @@ static int iscsi_has_ping_timed_out(struct iscsi_conn *conn) enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc) { - enum blk_eh_timer_return rc = BLK_EH_NOT_HANDLED; + enum blk_eh_timer_return rc = BLK_EH_DONE; struct iscsi_task *task = NULL, *running_task; struct iscsi_cls_session *cls_session; struct iscsi_session *session; @@ -1982,7 +1982,7 @@ enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc) * Raced with completion. Blk layer has taken ownership * so let timeout code complete it now. */ - rc = BLK_EH_HANDLED; + rc = BLK_EH_DONE; goto done; } @@ -1997,7 +1997,7 @@ enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc) if (unlikely(system_state != SYSTEM_RUNNING)) { sc->result = DID_NO_CONNECT << 16; ISCSI_DBG_EH(session, "sc on shutdown, handled\n"); - rc = BLK_EH_HANDLED; + rc = BLK_EH_DONE; goto done; } /* diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 7195cff51d4c..91f5e2c68dbc 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -2731,53 +2731,6 @@ proc_show_rdrv_40(struct seq_file *m, void *v) return proc_show_rdrv(m, m->private, 30, 39); } - -/* - * seq_file wrappers for procfile show routines. - */ -static int mega_proc_open(struct inode *inode, struct file *file) -{ - adapter_t *adapter = proc_get_parent_data(inode); - int (*show)(struct seq_file *, void *) = PDE_DATA(inode); - - return single_open(file, show, adapter); -} - -static const struct file_operations mega_proc_fops = { - .open = mega_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -/* - * Table of proc files we need to create. - */ -struct mega_proc_file { - const char *name; - unsigned short ptr_offset; - int (*show) (struct seq_file *m, void *v); -}; - -static const struct mega_proc_file mega_proc_files[] = { - { "config", offsetof(adapter_t, proc_read), proc_show_config }, - { "stat", offsetof(adapter_t, proc_stat), proc_show_stat }, - { "mailbox", offsetof(adapter_t, proc_mbox), proc_show_mbox }, -#if MEGA_HAVE_ENH_PROC - { "rebuild-rate", offsetof(adapter_t, proc_rr), proc_show_rebuild_rate }, - { "battery-status", offsetof(adapter_t, proc_battery), proc_show_battery }, - { "diskdrives-ch0", offsetof(adapter_t, proc_pdrvstat[0]), proc_show_pdrv_ch0 }, - { "diskdrives-ch1", offsetof(adapter_t, proc_pdrvstat[1]), proc_show_pdrv_ch1 }, - { "diskdrives-ch2", offsetof(adapter_t, proc_pdrvstat[2]), proc_show_pdrv_ch2 }, - { "diskdrives-ch3", offsetof(adapter_t, proc_pdrvstat[3]), proc_show_pdrv_ch3 }, - { "raiddrives-0-9", offsetof(adapter_t, proc_rdrvstat[0]), proc_show_rdrv_10 }, - { "raiddrives-10-19", offsetof(adapter_t, proc_rdrvstat[1]), proc_show_rdrv_20 }, - { "raiddrives-20-29", offsetof(adapter_t, proc_rdrvstat[2]), proc_show_rdrv_30 }, - { "raiddrives-30-39", offsetof(adapter_t, proc_rdrvstat[3]), proc_show_rdrv_40 }, -#endif - { NULL } -}; - /** * mega_create_proc_entry() * @index - index in soft state array @@ -2788,31 +2741,45 @@ static const struct mega_proc_file mega_proc_files[] = { static void mega_create_proc_entry(int index, struct proc_dir_entry *parent) { - const struct mega_proc_file *f; - adapter_t *adapter = hba_soft_state[index]; - struct proc_dir_entry *dir, *de, **ppde; - u8 string[16]; + adapter_t *adapter = hba_soft_state[index]; + struct proc_dir_entry *dir; + u8 string[16]; sprintf(string, "hba%d", adapter->host->host_no); - - dir = adapter->controller_proc_dir_entry = - proc_mkdir_data(string, 0, parent, adapter); - if(!dir) { + dir = proc_mkdir_data(string, 0, parent, adapter); + if (!dir) { dev_warn(&adapter->dev->dev, "proc_mkdir failed\n"); return; } - for (f = mega_proc_files; f->name; f++) { - de = proc_create_data(f->name, S_IRUSR, dir, &mega_proc_fops, - f->show); - if (!de) { - dev_warn(&adapter->dev->dev, "proc_create failed\n"); - return; - } - - ppde = (void *)adapter + f->ptr_offset; - *ppde = de; - } + proc_create_single_data("config", S_IRUSR, dir, + proc_show_config, adapter); + proc_create_single_data("stat", S_IRUSR, dir, + proc_show_stat, adapter); + proc_create_single_data("mailbox", S_IRUSR, dir, + proc_show_mbox, adapter); +#if MEGA_HAVE_ENH_PROC + proc_create_single_data("rebuild-rate", S_IRUSR, dir, + proc_show_rebuild_rate, adapter); + proc_create_single_data("battery-status", S_IRUSR, dir, + proc_show_battery, adapter); + proc_create_single_data("diskdrives-ch0", S_IRUSR, dir, + proc_show_pdrv_ch0, adapter); + proc_create_single_data("diskdrives-ch1", S_IRUSR, dir, + proc_show_pdrv_ch1, adapter); + proc_create_single_data("diskdrives-ch2", S_IRUSR, dir, + proc_show_pdrv_ch2, adapter); + proc_create_single_data("diskdrives-ch3", S_IRUSR, dir, + proc_show_pdrv_ch3, adapter); + proc_create_single_data("raiddrives-0-9", S_IRUSR, dir, + proc_show_rdrv_10, adapter); + proc_create_single_data("raiddrives-10-19", S_IRUSR, dir, + proc_show_rdrv_20, adapter); + proc_create_single_data("raiddrives-20-29", S_IRUSR, dir, + proc_show_rdrv_30, adapter); + proc_create_single_data("raiddrives-30-39", S_IRUSR, dir, + proc_show_rdrv_40, adapter); +#endif } #else @@ -4580,6 +4547,7 @@ megaraid_remove_one(struct pci_dev *pdev) { struct Scsi_Host *host = pci_get_drvdata(pdev); adapter_t *adapter = (adapter_t *)host->hostdata; + char buf[12] = { 0 }; scsi_remove_host(host); @@ -4594,44 +4562,8 @@ megaraid_remove_one(struct pci_dev *pdev) mega_free_sgl(adapter); -#ifdef CONFIG_PROC_FS - if (adapter->controller_proc_dir_entry) { - remove_proc_entry("stat", adapter->controller_proc_dir_entry); - remove_proc_entry("config", - adapter->controller_proc_dir_entry); - remove_proc_entry("mailbox", - adapter->controller_proc_dir_entry); -#if MEGA_HAVE_ENH_PROC - remove_proc_entry("rebuild-rate", - adapter->controller_proc_dir_entry); - remove_proc_entry("battery-status", - adapter->controller_proc_dir_entry); - - remove_proc_entry("diskdrives-ch0", - adapter->controller_proc_dir_entry); - remove_proc_entry("diskdrives-ch1", - adapter->controller_proc_dir_entry); - remove_proc_entry("diskdrives-ch2", - adapter->controller_proc_dir_entry); - remove_proc_entry("diskdrives-ch3", - adapter->controller_proc_dir_entry); - - remove_proc_entry("raiddrives-0-9", - adapter->controller_proc_dir_entry); - remove_proc_entry("raiddrives-10-19", - adapter->controller_proc_dir_entry); - remove_proc_entry("raiddrives-20-29", - adapter->controller_proc_dir_entry); - remove_proc_entry("raiddrives-30-39", - adapter->controller_proc_dir_entry); -#endif - { - char buf[12] = { 0 }; - sprintf(buf, "hba%d", adapter->host->host_no); - remove_proc_entry(buf, mega_proc_dir_entry); - } - } -#endif + sprintf(buf, "hba%d", adapter->host->host_no); + remove_proc_subtree(buf, mega_proc_dir_entry); pci_free_consistent(adapter->dev, MEGA_BUFFER_SIZE, adapter->mega_buffer, adapter->buf_dma_handle); diff --git a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h index 21eba2fd465a..18e85d9267ff 100644 --- a/drivers/scsi/megaraid.h +++ b/drivers/scsi/megaraid.h @@ -814,18 +814,6 @@ typedef struct { #ifdef CONFIG_PROC_FS struct proc_dir_entry *controller_proc_dir_entry; - struct proc_dir_entry *proc_read; - struct proc_dir_entry *proc_stat; - struct proc_dir_entry *proc_mbox; - -#if MEGA_HAVE_ENH_PROC - struct proc_dir_entry *proc_rr; - struct proc_dir_entry *proc_battery; -#define MAX_PROC_CHANNELS 4 - struct proc_dir_entry *proc_pdrvstat[MAX_PROC_CHANNELS]; - struct proc_dir_entry *proc_rdrvstat[MAX_PROC_CHANNELS]; -#endif - #endif int has_64bit_addr; /* are we using 64-bit addressing */ diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index b89c6e6c0589..ce656c466ca9 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -2772,7 +2772,7 @@ blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd) if (time_after(jiffies, scmd->jiffies_at_alloc + (scmd_timeout * 2) * HZ)) { - return BLK_EH_NOT_HANDLED; + return BLK_EH_DONE; } instance = (struct megasas_instance *)scmd->device->host->hostdata; diff --git a/drivers/scsi/mvumi.c b/drivers/scsi/mvumi.c index fe97401ad192..afd27165cd93 100644 --- a/drivers/scsi/mvumi.c +++ b/drivers/scsi/mvumi.c @@ -2155,7 +2155,7 @@ static enum blk_eh_timer_return mvumi_timed_out(struct scsi_cmnd *scmd) mvumi_return_cmd(mhba, cmd); spin_unlock_irqrestore(mhba->shost->host_lock, flags); - return BLK_EH_NOT_HANDLED; + return BLK_EH_DONE; } static int diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c index e18877177f1b..5a33e1ad9881 100644 --- a/drivers/scsi/osd/osd_initiator.c +++ b/drivers/scsi/osd/osd_initiator.c @@ -99,7 +99,7 @@ static int _osd_get_print_system_info(struct osd_dev *od, int nelem = ARRAY_SIZE(get_attrs), a = 0; int ret; - or = osd_start_request(od, GFP_KERNEL); + or = osd_start_request(od); if (!or) return -ENOMEM; @@ -409,16 +409,15 @@ static void _osd_request_free(struct osd_request *or) kfree(or); } -struct osd_request *osd_start_request(struct osd_dev *dev, gfp_t gfp) +struct osd_request *osd_start_request(struct osd_dev *dev) { struct osd_request *or; - or = _osd_request_alloc(gfp); + or = _osd_request_alloc(GFP_KERNEL); if (!or) return NULL; or->osd_dev = dev; - or->alloc_flags = gfp; or->timeout = dev->def_timeout; or->retries = OSD_REQ_RETRIES; @@ -546,7 +545,7 @@ static int _osd_realloc_seg(struct osd_request *or, if (seg->alloc_size >= max_bytes) return 0; - buff = krealloc(seg->buff, max_bytes, or->alloc_flags); + buff = krealloc(seg->buff, max_bytes, GFP_KERNEL); if (!buff) { OSD_ERR("Failed to Realloc %d-bytes was-%d\n", max_bytes, seg->alloc_size); @@ -728,7 +727,7 @@ static int _osd_req_list_objects(struct osd_request *or, _osd_req_encode_olist(or, list); WARN_ON(or->in.bio); - bio = bio_map_kern(q, list, len, or->alloc_flags); + bio = bio_map_kern(q, list, len, GFP_KERNEL); if (IS_ERR(bio)) { OSD_ERR("!!! Failed to allocate list_objects BIO\n"); return PTR_ERR(bio); @@ -1190,14 +1189,14 @@ static int _req_append_segment(struct osd_request *or, pad_buff = io->pad_buff; ret = blk_rq_map_kern(io->req->q, io->req, pad_buff, padding, - or->alloc_flags); + GFP_KERNEL); if (ret) return ret; io->total_bytes += padding; } ret = blk_rq_map_kern(io->req->q, io->req, seg->buff, seg->total_bytes, - or->alloc_flags); + GFP_KERNEL); if (ret) return ret; @@ -1564,14 +1563,14 @@ static int _osd_req_finalize_data_integrity(struct osd_request *or, * osd_finalize_request and helpers */ static struct request *_make_request(struct request_queue *q, bool has_write, - struct _osd_io_info *oii, gfp_t flags) + struct _osd_io_info *oii) { struct request *req; struct bio *bio = oii->bio; int ret; req = blk_get_request(q, has_write ? REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, - flags); + 0); if (IS_ERR(req)) return req; @@ -1589,13 +1588,12 @@ static struct request *_make_request(struct request_queue *q, bool has_write, static int _init_blk_request(struct osd_request *or, bool has_in, bool has_out) { - gfp_t flags = or->alloc_flags; struct scsi_device *scsi_device = or->osd_dev->scsi_device; struct request_queue *q = scsi_device->request_queue; struct request *req; int ret; - req = _make_request(q, has_out, has_out ? &or->out : &or->in, flags); + req = _make_request(q, has_out, has_out ? &or->out : &or->in); if (IS_ERR(req)) { ret = PTR_ERR(req); goto out; @@ -1611,7 +1609,7 @@ static int _init_blk_request(struct osd_request *or, or->out.req = req; if (has_in) { /* allocate bidi request */ - req = _make_request(q, false, &or->in, flags); + req = _make_request(q, false, &or->in); if (IS_ERR(req)) { OSD_DEBUG("blk_get_request for bidi failed\n"); ret = PTR_ERR(req); diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index 20ec1c01dbd5..2bbe797f8c3d 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c @@ -368,7 +368,7 @@ static int osst_execute(struct osst_request *SRpnt, const unsigned char *cmd, int write = (data_direction == DMA_TO_DEVICE); req = blk_get_request(SRpnt->stp->device->request_queue, - write ? REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, GFP_KERNEL); + write ? REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, 0); if (IS_ERR(req)) return DRIVER_ERROR << 24; diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 94c14ce94da2..0e13349dce57 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -1848,7 +1848,7 @@ static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc) struct iscsi_cls_session *session; struct iscsi_session *sess; unsigned long flags; - enum blk_eh_timer_return ret = BLK_EH_NOT_HANDLED; + enum blk_eh_timer_return ret = BLK_EH_DONE; session = starget_to_session(scsi_target(sc->device)); sess = session->dd_data; diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 946039117bf4..9c02ba2e7ef3 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -282,7 +282,7 @@ void scsi_eh_scmd_add(struct scsi_cmnd *scmd) enum blk_eh_timer_return scsi_times_out(struct request *req) { struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(req); - enum blk_eh_timer_return rtn = BLK_EH_NOT_HANDLED; + enum blk_eh_timer_return rtn = BLK_EH_DONE; struct Scsi_Host *host = scmd->device->host; trace_scsi_dispatch_cmd_timeout(scmd); @@ -294,7 +294,7 @@ enum blk_eh_timer_return scsi_times_out(struct request *req) if (host->hostt->eh_timed_out) rtn = host->hostt->eh_timed_out(scmd); - if (rtn == BLK_EH_NOT_HANDLED) { + if (rtn == BLK_EH_DONE) { if (scsi_abort_command(scmd) != SUCCESS) { set_host_byte(scmd, DID_TIME_OUT); scsi_eh_scmd_add(scmd); @@ -1933,11 +1933,7 @@ static void scsi_eh_lock_door(struct scsi_device *sdev) struct request *req; struct scsi_request *rq; - /* - * blk_get_request with GFP_KERNEL (__GFP_RECLAIM) sleeps until a - * request becomes available - */ - req = blk_get_request(sdev->request_queue, REQ_OP_SCSI_IN, GFP_KERNEL); + req = blk_get_request(sdev->request_queue, REQ_OP_SCSI_IN, 0); if (IS_ERR(req)) return; rq = scsi_req(req); diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index e9b4f279d29c..fb38aeff9dbd 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -265,7 +265,7 @@ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, struct scsi_request *rq; int ret = DRIVER_ERROR << 24; - req = blk_get_request_flags(sdev->request_queue, + req = blk_get_request(sdev->request_queue, data_direction == DMA_TO_DEVICE ? REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, BLK_MQ_REQ_PREEMPT); if (IS_ERR(req)) @@ -273,7 +273,7 @@ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, rq = scsi_req(req); if (bufflen && blk_rq_map_kern(sdev->request_queue, req, - buffer, bufflen, __GFP_RECLAIM)) + buffer, bufflen, GFP_NOIO)) goto out; rq->cmd_len = COMMAND_SIZE(cmd[0]); @@ -2149,27 +2149,6 @@ static int scsi_map_queues(struct blk_mq_tag_set *set) return blk_mq_map_queues(set); } -static u64 scsi_calculate_bounce_limit(struct Scsi_Host *shost) -{ - struct device *host_dev; - u64 bounce_limit = 0xffffffff; - - if (shost->unchecked_isa_dma) - return BLK_BOUNCE_ISA; - /* - * Platforms with virtual-DMA translation - * hardware have no practical limit. - */ - if (!PCI_DMA_BUS_IS_PHYS) - return BLK_BOUNCE_ANY; - - host_dev = scsi_get_device(shost); - if (host_dev && host_dev->dma_mask) - bounce_limit = (u64)dma_max_pfn(host_dev) << PAGE_SHIFT; - - return bounce_limit; -} - void __scsi_init_queue(struct Scsi_Host *shost, struct request_queue *q) { struct device *dev = shost->dma_dev; @@ -2189,7 +2168,8 @@ void __scsi_init_queue(struct Scsi_Host *shost, struct request_queue *q) } blk_queue_max_hw_sectors(q, shost->max_sectors); - blk_queue_bounce_limit(q, scsi_calculate_bounce_limit(shost)); + if (shost->unchecked_isa_dma) + blk_queue_bounce_limit(q, BLK_BOUNCE_ISA); blk_queue_segment_boundary(q, shost->dma_boundary); dma_set_seg_boundary(dev, shost->dma_boundary); diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index be3be0f9cb2d..1da3d71e9f61 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -2087,7 +2087,7 @@ fc_eh_timed_out(struct scsi_cmnd *scmd) if (rport->port_state == FC_PORTSTATE_BLOCKED) return BLK_EH_RESET_TIMER; - return BLK_EH_NOT_HANDLED; + return BLK_EH_DONE; } EXPORT_SYMBOL(fc_eh_timed_out); @@ -3591,10 +3591,9 @@ fc_bsg_job_timeout(struct request *req) } /* the blk_end_sync_io() doesn't check the error */ - if (!inflight) - return BLK_EH_NOT_HANDLED; - else - return BLK_EH_HANDLED; + if (inflight) + blk_mq_complete_request(req); + return BLK_EH_DONE; } /** @@ -3781,8 +3780,7 @@ fc_bsg_hostadd(struct Scsi_Host *shost, struct fc_host_attrs *fc_host) snprintf(bsg_name, sizeof(bsg_name), "fc_host%d", shost->host_no); - q = bsg_setup_queue(dev, bsg_name, fc_bsg_dispatch, i->f->dd_bsg_size, - NULL); + q = bsg_setup_queue(dev, bsg_name, fc_bsg_dispatch, i->f->dd_bsg_size); if (IS_ERR(q)) { dev_err(dev, "fc_host%d: bsg interface failed to initialize - setup queue\n", @@ -3827,8 +3825,8 @@ fc_bsg_rportadd(struct Scsi_Host *shost, struct fc_rport *rport) if (!i->f->bsg_request) return -ENOTSUPP; - q = bsg_setup_queue(dev, NULL, fc_bsg_dispatch, i->f->dd_bsg_size, - NULL); + q = bsg_setup_queue(dev, dev_name(dev), fc_bsg_dispatch, + i->f->dd_bsg_size); if (IS_ERR(q)) { dev_err(dev, "failed to setup bsg queue\n"); return PTR_ERR(q); diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 65f6c94f2e9b..6fd2fe210fc3 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -1542,7 +1542,7 @@ iscsi_bsg_host_add(struct Scsi_Host *shost, struct iscsi_cls_host *ihost) return -ENOTSUPP; snprintf(bsg_name, sizeof(bsg_name), "iscsi_host%d", shost->host_no); - q = bsg_setup_queue(dev, bsg_name, iscsi_bsg_host_dispatch, 0, NULL); + q = bsg_setup_queue(dev, bsg_name, iscsi_bsg_host_dispatch, 0); if (IS_ERR(q)) { shost_printk(KERN_ERR, shost, "bsg interface failed to " "initialize - no request queue\n"); diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index 08acbabfae07..e2953b416746 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c @@ -187,16 +187,6 @@ static int sas_smp_dispatch(struct bsg_job *job) return 0; } -static void sas_host_release(struct device *dev) -{ - struct Scsi_Host *shost = dev_to_shost(dev); - struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); - struct request_queue *q = sas_host->q; - - if (q) - blk_cleanup_queue(q); -} - static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy) { struct request_queue *q; @@ -208,7 +198,7 @@ static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy) if (rphy) { q = bsg_setup_queue(&rphy->dev, dev_name(&rphy->dev), - sas_smp_dispatch, 0, NULL); + sas_smp_dispatch, 0); if (IS_ERR(q)) return PTR_ERR(q); rphy->q = q; @@ -217,7 +207,7 @@ static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy) snprintf(name, sizeof(name), "sas_host%d", shost->host_no); q = bsg_setup_queue(&shost->shost_gendev, name, - sas_smp_dispatch, 0, sas_host_release); + sas_smp_dispatch, 0); if (IS_ERR(q)) return PTR_ERR(q); to_sas_host_attrs(shost)->q = q; @@ -260,8 +250,11 @@ static int sas_host_remove(struct transport_container *tc, struct device *dev, struct Scsi_Host *shost = dev_to_shost(dev); struct request_queue *q = to_sas_host_attrs(shost)->q; - if (q) + if (q) { bsg_unregister_queue(q); + blk_cleanup_queue(q); + } + return 0; } diff --git a/drivers/scsi/scsi_transport_srp.c b/drivers/scsi/scsi_transport_srp.c index 36f6190931bc..4e46fdb2d7c9 100644 --- a/drivers/scsi/scsi_transport_srp.c +++ b/drivers/scsi/scsi_transport_srp.c @@ -51,6 +51,8 @@ struct srp_internal { struct transport_container rport_attr_cont; }; +static int scsi_is_srp_rport(const struct device *dev); + #define to_srp_internal(tmpl) container_of(tmpl, struct srp_internal, t) #define dev_to_rport(d) container_of(d, struct srp_rport, dev) @@ -60,9 +62,24 @@ static inline struct Scsi_Host *rport_to_shost(struct srp_rport *r) return dev_to_shost(r->dev.parent); } +static int find_child_rport(struct device *dev, void *data) +{ + struct device **child = data; + + if (scsi_is_srp_rport(dev)) { + WARN_ON_ONCE(*child); + *child = dev; + } + return 0; +} + static inline struct srp_rport *shost_to_rport(struct Scsi_Host *shost) { - return transport_class_to_srp_rport(&shost->shost_gendev); + struct device *child = NULL; + + WARN_ON_ONCE(device_for_each_child(&shost->shost_gendev, &child, + find_child_rport) < 0); + return child ? dev_to_rport(child) : NULL; } /** @@ -587,7 +604,7 @@ EXPORT_SYMBOL(srp_reconnect_rport); * * If a timeout occurs while an rport is in the blocked state, ask the SCSI * EH to continue waiting (BLK_EH_RESET_TIMER). Otherwise let the SCSI core - * handle the timeout (BLK_EH_NOT_HANDLED). + * handle the timeout (BLK_EH_DONE). * * Note: This function is called from soft-IRQ context and with the request * queue lock held. @@ -600,9 +617,10 @@ enum blk_eh_timer_return srp_timed_out(struct scsi_cmnd *scmd) struct srp_rport *rport = shost_to_rport(shost); pr_debug("timeout for sdev %s\n", dev_name(&sdev->sdev_gendev)); - return rport->fast_io_fail_tmo < 0 && rport->dev_loss_tmo < 0 && + return rport && rport->fast_io_fail_tmo < 0 && + rport->dev_loss_tmo < 0 && i->f->reset_timer_if_blocked && scsi_device_blocked(sdev) ? - BLK_EH_RESET_TIMER : BLK_EH_NOT_HANDLED; + BLK_EH_RESET_TIMER : BLK_EH_DONE; } EXPORT_SYMBOL(srp_timed_out); diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index c198b96368dd..6fc58e2c99d3 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -66,7 +66,6 @@ static int sg_version_num = 30536; /* 2 digits for each component */ static char *sg_version_date = "20140603"; static int sg_proc_init(void); -static void sg_proc_cleanup(void); #endif #define SG_ALLOW_DIO_DEF 0 @@ -1661,7 +1660,7 @@ static void __exit exit_sg(void) { #ifdef CONFIG_SCSI_PROC_FS - sg_proc_cleanup(); + remove_proc_subtree("scsi/sg", NULL); #endif /* CONFIG_SCSI_PROC_FS */ scsi_unregister_interface(&sg_interface); class_destroy(sg_sysfs_class); @@ -1715,7 +1714,7 @@ sg_start_req(Sg_request *srp, unsigned char *cmd) * does not sleep except under memory pressure. */ rq = blk_get_request(q, hp->dxfer_direction == SG_DXFER_TO_DEV ? - REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, GFP_KERNEL); + REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, 0); if (IS_ERR(rq)) { kfree(long_cmdp); return PTR_ERR(rq); @@ -1894,7 +1893,7 @@ retry: num = (rem_sz > scatter_elem_sz_prev) ? scatter_elem_sz_prev : rem_sz; - schp->pages[k] = alloc_pages(gfp_mask, order); + schp->pages[k] = alloc_pages(gfp_mask | __GFP_ZERO, order); if (!schp->pages[k]) goto out; @@ -2274,11 +2273,6 @@ sg_get_dev(int dev) } #ifdef CONFIG_SCSI_PROC_FS - -static struct proc_dir_entry *sg_proc_sgp = NULL; - -static char sg_proc_sg_dirname[] = "scsi/sg"; - static int sg_proc_seq_show_int(struct seq_file *s, void *v); static int sg_proc_single_open_adio(struct inode *inode, struct file *file); @@ -2306,37 +2300,11 @@ static const struct file_operations dressz_fops = { }; static int sg_proc_seq_show_version(struct seq_file *s, void *v); -static int sg_proc_single_open_version(struct inode *inode, struct file *file); -static const struct file_operations version_fops = { - .owner = THIS_MODULE, - .open = sg_proc_single_open_version, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static int sg_proc_seq_show_devhdr(struct seq_file *s, void *v); -static int sg_proc_single_open_devhdr(struct inode *inode, struct file *file); -static const struct file_operations devhdr_fops = { - .owner = THIS_MODULE, - .open = sg_proc_single_open_devhdr, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static int sg_proc_seq_show_dev(struct seq_file *s, void *v); -static int sg_proc_open_dev(struct inode *inode, struct file *file); static void * dev_seq_start(struct seq_file *s, loff_t *pos); static void * dev_seq_next(struct seq_file *s, void *v, loff_t *pos); static void dev_seq_stop(struct seq_file *s, void *v); -static const struct file_operations dev_fops = { - .owner = THIS_MODULE, - .open = sg_proc_open_dev, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; static const struct seq_operations dev_seq_ops = { .start = dev_seq_start, .next = dev_seq_next, @@ -2345,14 +2313,6 @@ static const struct seq_operations dev_seq_ops = { }; static int sg_proc_seq_show_devstrs(struct seq_file *s, void *v); -static int sg_proc_open_devstrs(struct inode *inode, struct file *file); -static const struct file_operations devstrs_fops = { - .owner = THIS_MODULE, - .open = sg_proc_open_devstrs, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; static const struct seq_operations devstrs_seq_ops = { .start = dev_seq_start, .next = dev_seq_next, @@ -2361,14 +2321,6 @@ static const struct seq_operations devstrs_seq_ops = { }; static int sg_proc_seq_show_debug(struct seq_file *s, void *v); -static int sg_proc_open_debug(struct inode *inode, struct file *file); -static const struct file_operations debug_fops = { - .owner = THIS_MODULE, - .open = sg_proc_open_debug, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; static const struct seq_operations debug_seq_ops = { .start = dev_seq_start, .next = dev_seq_next, @@ -2376,50 +2328,23 @@ static const struct seq_operations debug_seq_ops = { .show = sg_proc_seq_show_debug, }; - -struct sg_proc_leaf { - const char * name; - const struct file_operations * fops; -}; - -static const struct sg_proc_leaf sg_proc_leaf_arr[] = { - {"allow_dio", &adio_fops}, - {"debug", &debug_fops}, - {"def_reserved_size", &dressz_fops}, - {"device_hdr", &devhdr_fops}, - {"devices", &dev_fops}, - {"device_strs", &devstrs_fops}, - {"version", &version_fops} -}; - static int sg_proc_init(void) { - int num_leaves = ARRAY_SIZE(sg_proc_leaf_arr); - int k; + struct proc_dir_entry *p; - sg_proc_sgp = proc_mkdir(sg_proc_sg_dirname, NULL); - if (!sg_proc_sgp) + p = proc_mkdir("scsi/sg", NULL); + if (!p) return 1; - for (k = 0; k < num_leaves; ++k) { - const struct sg_proc_leaf *leaf = &sg_proc_leaf_arr[k]; - umode_t mask = leaf->fops->write ? S_IRUGO | S_IWUSR : S_IRUGO; - proc_create(leaf->name, mask, sg_proc_sgp, leaf->fops); - } - return 0; -} -static void -sg_proc_cleanup(void) -{ - int k; - int num_leaves = ARRAY_SIZE(sg_proc_leaf_arr); - - if (!sg_proc_sgp) - return; - for (k = 0; k < num_leaves; ++k) - remove_proc_entry(sg_proc_leaf_arr[k].name, sg_proc_sgp); - remove_proc_entry(sg_proc_sg_dirname, NULL); + proc_create("allow_dio", S_IRUGO | S_IWUSR, p, &adio_fops); + proc_create_seq("debug", S_IRUGO, p, &debug_seq_ops); + proc_create("def_reserved_size", S_IRUGO | S_IWUSR, p, &dressz_fops); + proc_create_single("device_hdr", S_IRUGO, p, sg_proc_seq_show_devhdr); + proc_create_seq("devices", S_IRUGO, p, &dev_seq_ops); + proc_create_seq("device_strs", S_IRUGO, p, &devstrs_seq_ops); + proc_create_single("version", S_IRUGO, p, sg_proc_seq_show_version); + return 0; } @@ -2482,22 +2407,12 @@ static int sg_proc_seq_show_version(struct seq_file *s, void *v) return 0; } -static int sg_proc_single_open_version(struct inode *inode, struct file *file) -{ - return single_open(file, sg_proc_seq_show_version, NULL); -} - static int sg_proc_seq_show_devhdr(struct seq_file *s, void *v) { seq_puts(s, "host\tchan\tid\tlun\ttype\topens\tqdepth\tbusy\tonline\n"); return 0; } -static int sg_proc_single_open_devhdr(struct inode *inode, struct file *file) -{ - return single_open(file, sg_proc_seq_show_devhdr, NULL); -} - struct sg_proc_deviter { loff_t index; size_t max; @@ -2531,11 +2446,6 @@ static void dev_seq_stop(struct seq_file *s, void *v) kfree(s->private); } -static int sg_proc_open_dev(struct inode *inode, struct file *file) -{ - return seq_open(file, &dev_seq_ops); -} - static int sg_proc_seq_show_dev(struct seq_file *s, void *v) { struct sg_proc_deviter * it = (struct sg_proc_deviter *) v; @@ -2562,11 +2472,6 @@ static int sg_proc_seq_show_dev(struct seq_file *s, void *v) return 0; } -static int sg_proc_open_devstrs(struct inode *inode, struct file *file) -{ - return seq_open(file, &devstrs_seq_ops); -} - static int sg_proc_seq_show_devstrs(struct seq_file *s, void *v) { struct sg_proc_deviter * it = (struct sg_proc_deviter *) v; @@ -2650,11 +2555,6 @@ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp) } } -static int sg_proc_open_debug(struct inode *inode, struct file *file) -{ - return seq_open(file, &debug_seq_ops); -} - static int sg_proc_seq_show_debug(struct seq_file *s, void *v) { struct sg_proc_deviter * it = (struct sg_proc_deviter *) v; diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c index 2a21f2d48592..35fab1e18adc 100644 --- a/drivers/scsi/sr_ioctl.c +++ b/drivers/scsi/sr_ioctl.c @@ -188,9 +188,13 @@ int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc) struct scsi_device *SDev; struct scsi_sense_hdr sshdr; int result, err = 0, retries = 0; + unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE], *senseptr = NULL; SDev = cd->device; + if (cgc->sense) + senseptr = sense_buffer; + retry: if (!scsi_block_when_processing_errors(SDev)) { err = -ENODEV; @@ -198,10 +202,12 @@ int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc) } result = scsi_execute(SDev, cgc->cmd, cgc->data_direction, - cgc->buffer, cgc->buflen, - (unsigned char *)cgc->sense, &sshdr, + cgc->buffer, cgc->buflen, senseptr, &sshdr, cgc->timeout, IOCTL_RETRIES, 0, 0, NULL); + if (cgc->sense) + memcpy(cgc->sense, sense_buffer, sizeof(*cgc->sense)); + /* Minimal error checking. Ignore cases we know about, and report the rest. */ if (driver_byte(result) != 0) { switch (sshdr.sense_key) { diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 6c399480783d..a427ce9497be 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -545,7 +545,7 @@ static int st_scsi_execute(struct st_request *SRpnt, const unsigned char *cmd, req = blk_get_request(SRpnt->stp->device->request_queue, data_direction == DMA_TO_DEVICE ? - REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, GFP_KERNEL); + REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, 0); if (IS_ERR(req)) return DRIVER_ERROR << 24; rq = scsi_req(req); diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 00e79057f870..d0a1674915a1 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -6497,12 +6497,12 @@ static enum blk_eh_timer_return ufshcd_eh_timed_out(struct scsi_cmnd *scmd) bool found = false; if (!scmd || !scmd->device || !scmd->device->host) - return BLK_EH_NOT_HANDLED; + return BLK_EH_DONE; host = scmd->device->host; hba = shost_priv(host); if (!hba) - return BLK_EH_NOT_HANDLED; + return BLK_EH_DONE; spin_lock_irqsave(host->host_lock, flags); @@ -6520,7 +6520,7 @@ static enum blk_eh_timer_return ufshcd_eh_timed_out(struct scsi_cmnd *scmd) * SCSI command was not actually dispatched to UFS driver, otherwise * let SCSI layer handle the error as usual. */ - return found ? BLK_EH_NOT_HANDLED : BLK_EH_RESET_TIMER; + return found ? BLK_EH_DONE : BLK_EH_RESET_TIMER; } static const struct attribute_group *ufshcd_driver_groups[] = { diff --git a/drivers/soc/lantiq/gphy.c b/drivers/soc/lantiq/gphy.c index 8d8659463b3e..feeb17cebc25 100644 --- a/drivers/soc/lantiq/gphy.c +++ b/drivers/soc/lantiq/gphy.c @@ -30,7 +30,6 @@ struct xway_gphy_priv { struct clk *gphy_clk_gate; struct reset_control *gphy_reset; struct reset_control *gphy_reset2; - struct notifier_block gphy_reboot_nb; void __iomem *membase; char *fw_name; }; @@ -64,24 +63,6 @@ static const struct of_device_id xway_gphy_match[] = { }; MODULE_DEVICE_TABLE(of, xway_gphy_match); -static struct xway_gphy_priv *to_xway_gphy_priv(struct notifier_block *nb) -{ - return container_of(nb, struct xway_gphy_priv, gphy_reboot_nb); -} - -static int xway_gphy_reboot_notify(struct notifier_block *reboot_nb, - unsigned long code, void *unused) -{ - struct xway_gphy_priv *priv = to_xway_gphy_priv(reboot_nb); - - if (priv) { - reset_control_assert(priv->gphy_reset); - reset_control_assert(priv->gphy_reset2); - } - - return NOTIFY_DONE; -} - static int xway_gphy_load(struct device *dev, struct xway_gphy_priv *priv, dma_addr_t *dev_addr) { @@ -205,14 +186,6 @@ static int xway_gphy_probe(struct platform_device *pdev) reset_control_deassert(priv->gphy_reset); reset_control_deassert(priv->gphy_reset2); - /* assert the gphy reset because it can hang after a reboot: */ - priv->gphy_reboot_nb.notifier_call = xway_gphy_reboot_notify; - priv->gphy_reboot_nb.priority = -1; - - ret = register_reboot_notifier(&priv->gphy_reboot_nb); - if (ret) - dev_warn(dev, "Failed to register reboot notifier\n"); - platform_set_drvdata(pdev, priv); return ret; @@ -220,21 +193,12 @@ static int xway_gphy_probe(struct platform_device *pdev) static int xway_gphy_remove(struct platform_device *pdev) { - struct device *dev = &pdev->dev; struct xway_gphy_priv *priv = platform_get_drvdata(pdev); - int ret; - - reset_control_assert(priv->gphy_reset); - reset_control_assert(priv->gphy_reset2); iowrite32be(0, priv->membase); clk_disable_unprepare(priv->gphy_clk_gate); - ret = unregister_reboot_notifier(&priv->gphy_reboot_nb); - if (ret) - dev_warn(dev, "Failed to unregister reboot notifier\n"); - return 0; } diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index d9fcdb592b39..3e3d12ce4587 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -559,22 +559,28 @@ EXPORT_SYMBOL(tegra_powergate_remove_clamping); int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk, struct reset_control *rst) { - struct tegra_powergate pg; + struct tegra_powergate *pg; int err; if (!tegra_powergate_is_available(id)) return -EINVAL; - pg.id = id; - pg.clks = &clk; - pg.num_clks = 1; - pg.reset = rst; - pg.pmc = pmc; + pg = kzalloc(sizeof(*pg), GFP_KERNEL); + if (!pg) + return -ENOMEM; - err = tegra_powergate_power_up(&pg, false); + pg->id = id; + pg->clks = &clk; + pg->num_clks = 1; + pg->reset = rst; + pg->pmc = pmc; + + err = tegra_powergate_power_up(pg, false); if (err) pr_err("failed to turn on partition %d: %d\n", id, err); + kfree(pg); + return err; } EXPORT_SYMBOL(tegra_powergate_sequence_power_up); diff --git a/drivers/soundwire/bus_type.c b/drivers/soundwire/bus_type.c index d5f3a70c06b0..283b2832728e 100644 --- a/drivers/soundwire/bus_type.c +++ b/drivers/soundwire/bus_type.c @@ -83,17 +83,16 @@ static int sdw_drv_probe(struct device *dev) * attach to power domain but don't turn on (last arg) */ ret = dev_pm_domain_attach(dev, false); - if (ret != -EPROBE_DEFER) { - ret = drv->probe(slave, id); - if (ret) { - dev_err(dev, "Probe of %s failed: %d\n", drv->name, ret); - dev_pm_domain_detach(dev, false); - } - } - if (ret) return ret; + ret = drv->probe(slave, id); + if (ret) { + dev_err(dev, "Probe of %s failed: %d\n", drv->name, ret); + dev_pm_domain_detach(dev, false); + return ret; + } + /* device is probed so let's read the properties now */ if (slave->ops && slave->ops->read_prop) slave->ops->read_prop(slave); diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 2d4146ce2f1b..ad5d68e1dab7 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -47,6 +47,13 @@ config SPI_MASTER if SPI_MASTER +config SPI_MEM + bool "SPI memory extension" + help + Enable this option if you want to enable the SPI memory extension. + This extension is meant to simplify interaction with SPI memories + by providing a high-level interface to send memory-like commands. + comment "SPI Master Controller Drivers" config SPI_ALTERA @@ -71,7 +78,6 @@ config SPI_ARMADA_3700 config SPI_ATMEL tristate "Atmel SPI Controller" - depends on HAS_DMA depends on ARCH_AT91 || COMPILE_TEST help This selects a driver for the Atmel SPI Controller, present on @@ -115,14 +121,6 @@ config SPI_BCM2835AUX "universal SPI master", and the regular SPI controller. This driver is for the universal/auxiliary SPI controller. -config SPI_BCM53XX - tristate "Broadcom BCM53xx SPI controller" - depends on ARCH_BCM_5301X - depends on BCMA_POSSIBLE - select BCMA - help - Enable support for the SPI controller on Broadcom BCM53xx ARM SoCs. - config SPI_BCM63XX tristate "Broadcom BCM63xx SPI controller" depends on BCM63XX || COMPILE_TEST @@ -233,7 +231,6 @@ config SPI_EFM32 config SPI_EP93XX tristate "Cirrus Logic EP93xx SPI controller" - depends on HAS_DMA depends on ARCH_EP93XX || COMPILE_TEST help This enables using the Cirrus EP93xx SPI controller in master @@ -355,7 +352,6 @@ config SPI_FSL_SPI config SPI_FSL_DSPI tristate "Freescale DSPI controller" select REGMAP_MMIO - depends on HAS_DMA depends on SOC_VF610 || SOC_LS1021A || ARCH_LAYERSCAPE || M5441x || COMPILE_TEST help This enables support for the Freescale DSPI controller in master @@ -431,7 +427,6 @@ config SPI_OMAP_UWIRE config SPI_OMAP24XX tristate "McSPI driver for OMAP" - depends on HAS_DMA depends on ARCH_OMAP2PLUS || COMPILE_TEST select SG_SPLIT help @@ -440,7 +435,6 @@ config SPI_OMAP24XX config SPI_TI_QSPI tristate "DRA7xxx QSPI controller support" - depends on HAS_DMA depends on ARCH_OMAP2PLUS || COMPILE_TEST help QSPI master controller for DRA7xxx used for flash devices. @@ -469,7 +463,6 @@ config SPI_PIC32 config SPI_PIC32_SQI tristate "Microchip PIC32 Quad SPI driver" depends on MACH_PIC32 || COMPILE_TEST - depends on HAS_DMA help SPI driver for PIC32 Quad SPI controller. @@ -572,7 +565,7 @@ config SPI_SC18IS602 config SPI_SH_MSIOF tristate "SuperH MSIOF SPI controller" - depends on HAVE_CLK && HAS_DMA + depends on HAVE_CLK depends on ARCH_SHMOBILE || ARCH_RENESAS || COMPILE_TEST help SPI driver for SuperH and SH Mobile MSIOF blocks. @@ -650,7 +643,7 @@ config SPI_MXS config SPI_TEGRA114 tristate "NVIDIA Tegra114 SPI Controller" depends on (ARCH_TEGRA && TEGRA20_APB_DMA) || COMPILE_TEST - depends on RESET_CONTROLLER && HAS_DMA + depends on RESET_CONTROLLER help SPI driver for NVIDIA Tegra114 SPI Controller interface. This controller is different than the older SoCs SPI controller and also register interface @@ -668,7 +661,7 @@ config SPI_TEGRA20_SFLASH config SPI_TEGRA20_SLINK tristate "Nvidia Tegra20/Tegra30 SLINK Controller" depends on (ARCH_TEGRA && TEGRA20_APB_DMA) || COMPILE_TEST - depends on RESET_CONTROLLER && HAS_DMA + depends on RESET_CONTROLLER help SPI driver for Nvidia Tegra20/Tegra30 SLINK Controller interface. diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index b935f10eb961..cb1f4378b87c 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -8,6 +8,7 @@ ccflags-$(CONFIG_SPI_DEBUG) := -DDEBUG # small core, mostly translating board-specific # config declarations into driver model code obj-$(CONFIG_SPI_MASTER) += spi.o +obj-$(CONFIG_SPI_MEM) += spi-mem.o obj-$(CONFIG_SPI_SPIDEV) += spidev.o obj-$(CONFIG_SPI_LOOPBACK_TEST) += spi-loopback-test.o @@ -20,7 +21,6 @@ obj-$(CONFIG_SPI_AU1550) += spi-au1550.o obj-$(CONFIG_SPI_AXI_SPI_ENGINE) += spi-axi-spi-engine.o obj-$(CONFIG_SPI_BCM2835) += spi-bcm2835.o obj-$(CONFIG_SPI_BCM2835AUX) += spi-bcm2835aux.o -obj-$(CONFIG_SPI_BCM53XX) += spi-bcm53xx.o obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63xx.o obj-$(CONFIG_SPI_BCM63XX_HSSPI) += spi-bcm63xx-hsspi.o obj-$(CONFIG_SPI_BCM_QSPI) += spi-iproc-qspi.o spi-brcmstb-qspi.o spi-bcm-qspi.o diff --git a/drivers/spi/internals.h b/drivers/spi/internals.h new file mode 100644 index 000000000000..4a28a8395552 --- /dev/null +++ b/drivers/spi/internals.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2018 Exceet Electronics GmbH + * Copyright (C) 2018 Bootlin + * + * Author: Boris Brezillon <boris.brezillon@bootlin.com> + * + * Helpers needed by the spi or spi-mem logic. Should not be used outside of + * spi-mem.c and spi.c. + */ + +#ifndef __LINUX_SPI_INTERNALS_H +#define __LINUX_SPI_INTERNALS_H + +#include <linux/device.h> +#include <linux/dma-direction.h> +#include <linux/scatterlist.h> +#include <linux/spi/spi.h> + +void spi_flush_queue(struct spi_controller *ctrl); + +#ifdef CONFIG_HAS_DMA +int spi_map_buf(struct spi_controller *ctlr, struct device *dev, + struct sg_table *sgt, void *buf, size_t len, + enum dma_data_direction dir); +void spi_unmap_buf(struct spi_controller *ctlr, struct device *dev, + struct sg_table *sgt, enum dma_data_direction dir); +#else /* !CONFIG_HAS_DMA */ +static inline int spi_map_buf(struct spi_controller *ctlr, struct device *dev, + struct sg_table *sgt, void *buf, size_t len, + enum dma_data_direction dir) +{ + return -EINVAL; +} + +static inline void spi_unmap_buf(struct spi_controller *ctlr, + struct device *dev, struct sg_table *sgt, + enum dma_data_direction dir) +{ +} +#endif /* CONFIG_HAS_DMA */ + +#endif /* __LINUX_SPI_INTERNALS_H */ diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c index 6573152ce893..8612525fa4e3 100644 --- a/drivers/spi/spi-bcm-qspi.c +++ b/drivers/spi/spi-bcm-qspi.c @@ -30,6 +30,7 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/spi/spi.h> +#include <linux/spi/spi-mem.h> #include <linux/sysfs.h> #include <linux/types.h> #include "spi-bcm-qspi.h" @@ -215,10 +216,10 @@ struct bcm_qspi { int bspi_maj_rev; int bspi_min_rev; int bspi_enabled; - struct spi_flash_read_message *bspi_rf_msg; - u32 bspi_rf_msg_idx; - u32 bspi_rf_msg_len; - u32 bspi_rf_msg_status; + const struct spi_mem_op *bspi_rf_op; + u32 bspi_rf_op_idx; + u32 bspi_rf_op_len; + u32 bspi_rf_op_status; struct bcm_xfer_mode xfer_mode; u32 s3_strap_override_ctrl; bool bspi_mode; @@ -313,26 +314,26 @@ static inline void bcm_qspi_bspi_lr_clear(struct bcm_qspi *qspi) static void bcm_qspi_bspi_lr_data_read(struct bcm_qspi *qspi) { - u32 *buf = (u32 *)qspi->bspi_rf_msg->buf; + u32 *buf = (u32 *)qspi->bspi_rf_op->data.buf.in; u32 data = 0; - dev_dbg(&qspi->pdev->dev, "xfer %p rx %p rxlen %d\n", qspi->bspi_rf_msg, - qspi->bspi_rf_msg->buf, qspi->bspi_rf_msg_len); + dev_dbg(&qspi->pdev->dev, "xfer %p rx %p rxlen %d\n", qspi->bspi_rf_op, + qspi->bspi_rf_op->data.buf.in, qspi->bspi_rf_op_len); while (!bcm_qspi_bspi_lr_is_fifo_empty(qspi)) { data = bcm_qspi_bspi_lr_read_fifo(qspi); - if (likely(qspi->bspi_rf_msg_len >= 4) && + if (likely(qspi->bspi_rf_op_len >= 4) && IS_ALIGNED((uintptr_t)buf, 4)) { - buf[qspi->bspi_rf_msg_idx++] = data; - qspi->bspi_rf_msg_len -= 4; + buf[qspi->bspi_rf_op_idx++] = data; + qspi->bspi_rf_op_len -= 4; } else { /* Read out remaining bytes, make sure*/ - u8 *cbuf = (u8 *)&buf[qspi->bspi_rf_msg_idx]; + u8 *cbuf = (u8 *)&buf[qspi->bspi_rf_op_idx]; data = cpu_to_le32(data); - while (qspi->bspi_rf_msg_len) { + while (qspi->bspi_rf_op_len) { *cbuf++ = (u8)data; data >>= 8; - qspi->bspi_rf_msg_len--; + qspi->bspi_rf_op_len--; } } } @@ -349,14 +350,12 @@ static void bcm_qspi_bspi_set_xfer_params(struct bcm_qspi *qspi, u8 cmd_byte, } static int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi, - struct spi_flash_read_message *msg, - int hp) + const struct spi_mem_op *op, int hp) { int bpc = 0, bpp = 0; - u8 command = msg->read_opcode; - int width = msg->data_nbits ? msg->data_nbits : SPI_NBITS_SINGLE; - int addrlen = msg->addr_width; - int addr_nbits = msg->addr_nbits ? msg->addr_nbits : SPI_NBITS_SINGLE; + u8 command = op->cmd.opcode; + int width = op->cmd.buswidth ? op->cmd.buswidth : SPI_NBITS_SINGLE; + int addrlen = op->addr.nbytes * 8; int flex_mode = 1; dev_dbg(&qspi->pdev->dev, "set flex mode w %x addrlen %x hp %d\n", @@ -365,7 +364,7 @@ static int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi, if (addrlen == BSPI_ADDRLEN_4BYTES) bpp = BSPI_BPP_ADDR_SELECT_MASK; - bpp |= msg->dummy_bytes * (8/addr_nbits); + bpp |= (op->dummy.nbytes * 8) / op->dummy.buswidth; switch (width) { case SPI_NBITS_SINGLE: @@ -397,11 +396,10 @@ static int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi, } static int bcm_qspi_bspi_set_override(struct bcm_qspi *qspi, - struct spi_flash_read_message *msg, - int hp) + const struct spi_mem_op *op, int hp) { - int width = msg->data_nbits ? msg->data_nbits : SPI_NBITS_SINGLE; - int addrlen = msg->addr_width; + int width = op->data.buswidth ? op->data.buswidth : SPI_NBITS_SINGLE; + int addrlen = op->addr.nbytes; u32 data = bcm_qspi_read(qspi, BSPI, BSPI_STRAP_OVERRIDE_CTRL); dev_dbg(&qspi->pdev->dev, "set override mode w %x addrlen %x hp %d\n", @@ -437,17 +435,17 @@ static int bcm_qspi_bspi_set_override(struct bcm_qspi *qspi, /* set the override mode */ data |= BSPI_STRAP_OVERRIDE_CTRL_OVERRIDE; bcm_qspi_write(qspi, BSPI, BSPI_STRAP_OVERRIDE_CTRL, data); - bcm_qspi_bspi_set_xfer_params(qspi, msg->read_opcode, 0, 0, 0); + bcm_qspi_bspi_set_xfer_params(qspi, op->cmd.opcode, 0, 0, 0); return 0; } static int bcm_qspi_bspi_set_mode(struct bcm_qspi *qspi, - struct spi_flash_read_message *msg, int hp) + const struct spi_mem_op *op, int hp) { int error = 0; - int width = msg->data_nbits ? msg->data_nbits : SPI_NBITS_SINGLE; - int addrlen = msg->addr_width; + int width = op->data.buswidth ? op->data.buswidth : SPI_NBITS_SINGLE; + int addrlen = op->addr.nbytes; /* default mode */ qspi->xfer_mode.flex_mode = true; @@ -460,12 +458,12 @@ static int bcm_qspi_bspi_set_mode(struct bcm_qspi *qspi, if (val & mask || qspi->s3_strap_override_ctrl & mask) { qspi->xfer_mode.flex_mode = false; bcm_qspi_write(qspi, BSPI, BSPI_FLEX_MODE_ENABLE, 0); - error = bcm_qspi_bspi_set_override(qspi, msg, hp); + error = bcm_qspi_bspi_set_override(qspi, op, hp); } } if (qspi->xfer_mode.flex_mode) - error = bcm_qspi_bspi_set_flex_mode(qspi, msg, hp); + error = bcm_qspi_bspi_set_flex_mode(qspi, op, hp); if (error) { dev_warn(&qspi->pdev->dev, @@ -802,19 +800,20 @@ done: return slot; } -static int bcm_qspi_bspi_flash_read(struct spi_device *spi, - struct spi_flash_read_message *msg) +static int bcm_qspi_bspi_exec_mem_op(struct spi_device *spi, + const struct spi_mem_op *op) { struct bcm_qspi *qspi = spi_master_get_devdata(spi->master); - u32 addr = 0, len, rdlen, len_words; + u32 addr = 0, len, rdlen, len_words, from = 0; int ret = 0; unsigned long timeo = msecs_to_jiffies(100); struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc; if (bcm_qspi_bspi_ver_three(qspi)) - if (msg->addr_width == BSPI_ADDRLEN_4BYTES) + if (op->addr.nbytes == BSPI_ADDRLEN_4BYTES) return -EIO; + from = op->addr.val; bcm_qspi_chip_select(qspi, spi->chip_select); bcm_qspi_write(qspi, MSPI, MSPI_WRITE_LOCK, 0); @@ -823,15 +822,15 @@ static int bcm_qspi_bspi_flash_read(struct spi_device *spi, * the upper address byte to bspi */ if (bcm_qspi_bspi_ver_three(qspi) == false) { - addr = msg->from & 0xff000000; + addr = from & 0xff000000; bcm_qspi_write(qspi, BSPI, BSPI_BSPI_FLASH_UPPER_ADDR_BYTE, addr); } if (!qspi->xfer_mode.flex_mode) - addr = msg->from; + addr = from; else - addr = msg->from & 0x00ffffff; + addr = from & 0x00ffffff; if (bcm_qspi_bspi_ver_three(qspi) == true) addr = (addr + 0xc00000) & 0xffffff; @@ -840,8 +839,8 @@ static int bcm_qspi_bspi_flash_read(struct spi_device *spi, * read into the entire buffer by breaking the reads * into RAF buffer read lengths */ - len = msg->len; - qspi->bspi_rf_msg_idx = 0; + len = op->data.nbytes; + qspi->bspi_rf_op_idx = 0; do { if (len > BSPI_READ_LENGTH) @@ -852,9 +851,9 @@ static int bcm_qspi_bspi_flash_read(struct spi_device *spi, reinit_completion(&qspi->bspi_done); bcm_qspi_enable_bspi(qspi); len_words = (rdlen + 3) >> 2; - qspi->bspi_rf_msg = msg; - qspi->bspi_rf_msg_status = 0; - qspi->bspi_rf_msg_len = rdlen; + qspi->bspi_rf_op = op; + qspi->bspi_rf_op_status = 0; + qspi->bspi_rf_op_len = rdlen; dev_dbg(&qspi->pdev->dev, "bspi xfr addr 0x%x len 0x%x", addr, rdlen); bcm_qspi_write(qspi, BSPI, BSPI_RAF_START_ADDR, addr); @@ -879,7 +878,6 @@ static int bcm_qspi_bspi_flash_read(struct spi_device *spi, } /* set msg return length */ - msg->retlen += rdlen; addr += rdlen; len -= rdlen; } while (len); @@ -914,61 +912,63 @@ static int bcm_qspi_transfer_one(struct spi_master *master, return 0; } -static int bcm_qspi_mspi_flash_read(struct spi_device *spi, - struct spi_flash_read_message *msg) +static int bcm_qspi_mspi_exec_mem_op(struct spi_device *spi, + const struct spi_mem_op *op) { - struct bcm_qspi *qspi = spi_master_get_devdata(spi->master); + struct spi_master *master = spi->master; + struct bcm_qspi *qspi = spi_master_get_devdata(master); struct spi_transfer t[2]; - u8 cmd[6]; - int ret; + u8 cmd[6] = { }; + int ret, i; memset(cmd, 0, sizeof(cmd)); memset(t, 0, sizeof(t)); /* tx */ /* opcode is in cmd[0] */ - cmd[0] = msg->read_opcode; - cmd[1] = msg->from >> (msg->addr_width * 8 - 8); - cmd[2] = msg->from >> (msg->addr_width * 8 - 16); - cmd[3] = msg->from >> (msg->addr_width * 8 - 24); - cmd[4] = msg->from >> (msg->addr_width * 8 - 32); + cmd[0] = op->cmd.opcode; + for (i = 0; i < op->addr.nbytes; i++) + cmd[1 + i] = op->addr.val >> (8 * (op->addr.nbytes - i - 1)); + t[0].tx_buf = cmd; - t[0].len = msg->addr_width + msg->dummy_bytes + 1; + t[0].len = op->addr.nbytes + op->dummy.nbytes + 1; t[0].bits_per_word = spi->bits_per_word; - t[0].tx_nbits = msg->opcode_nbits; + t[0].tx_nbits = op->cmd.buswidth; /* lets mspi know that this is not last transfer */ qspi->trans_pos.mspi_last_trans = false; - ret = bcm_qspi_transfer_one(spi->master, spi, &t[0]); + ret = bcm_qspi_transfer_one(master, spi, &t[0]); /* rx */ qspi->trans_pos.mspi_last_trans = true; if (!ret) { /* rx */ - t[1].rx_buf = msg->buf; - t[1].len = msg->len; - t[1].rx_nbits = msg->data_nbits; + t[1].rx_buf = op->data.buf.in; + t[1].len = op->data.nbytes; + t[1].rx_nbits = op->data.buswidth; t[1].bits_per_word = spi->bits_per_word; - ret = bcm_qspi_transfer_one(spi->master, spi, &t[1]); + ret = bcm_qspi_transfer_one(master, spi, &t[1]); } - if (!ret) - msg->retlen = msg->len; - return ret; } -static int bcm_qspi_flash_read(struct spi_device *spi, - struct spi_flash_read_message *msg) +static int bcm_qspi_exec_mem_op(struct spi_mem *mem, + const struct spi_mem_op *op) { + struct spi_device *spi = mem->spi; struct bcm_qspi *qspi = spi_master_get_devdata(spi->master); int ret = 0; bool mspi_read = false; - u32 addr, len; + u32 addr = 0, len; u_char *buf; - buf = msg->buf; - addr = msg->from; - len = msg->len; + if (!op->data.nbytes || !op->addr.nbytes || op->addr.nbytes > 4 || + op->data.dir != SPI_MEM_DATA_IN) + return -ENOTSUPP; + + buf = op->data.buf.in; + addr = op->addr.val; + len = op->data.nbytes; if (bcm_qspi_bspi_ver_three(qspi) == true) { /* @@ -990,12 +990,12 @@ static int bcm_qspi_flash_read(struct spi_device *spi, mspi_read = true; if (mspi_read) - return bcm_qspi_mspi_flash_read(spi, msg); + return bcm_qspi_mspi_exec_mem_op(spi, op); - ret = bcm_qspi_bspi_set_mode(qspi, msg, -1); + ret = bcm_qspi_bspi_set_mode(qspi, op, -1); if (!ret) - ret = bcm_qspi_bspi_flash_read(spi, msg); + ret = bcm_qspi_bspi_exec_mem_op(spi, op); return ret; } @@ -1034,10 +1034,10 @@ static irqreturn_t bcm_qspi_bspi_lr_l2_isr(int irq, void *dev_id) struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc; u32 status = qspi_dev_id->irqp->mask; - if (qspi->bspi_enabled && qspi->bspi_rf_msg) { + if (qspi->bspi_enabled && qspi->bspi_rf_op) { bcm_qspi_bspi_lr_data_read(qspi); - if (qspi->bspi_rf_msg_len == 0) { - qspi->bspi_rf_msg = NULL; + if (qspi->bspi_rf_op_len == 0) { + qspi->bspi_rf_op = NULL; if (qspi->soc_intc) { /* disable soc BSPI interrupt */ soc_intc->bcm_qspi_int_set(soc_intc, BSPI_DONE, @@ -1046,7 +1046,7 @@ static irqreturn_t bcm_qspi_bspi_lr_l2_isr(int irq, void *dev_id) status = INTR_BSPI_LR_SESSION_DONE_MASK; } - if (qspi->bspi_rf_msg_status) + if (qspi->bspi_rf_op_status) bcm_qspi_bspi_lr_clear(qspi); else bcm_qspi_bspi_flush_prefetch_buffers(qspi); @@ -1058,7 +1058,7 @@ static irqreturn_t bcm_qspi_bspi_lr_l2_isr(int irq, void *dev_id) } status &= INTR_BSPI_LR_SESSION_DONE_MASK; - if (qspi->bspi_enabled && status && qspi->bspi_rf_msg_len == 0) + if (qspi->bspi_enabled && status && qspi->bspi_rf_op_len == 0) complete(&qspi->bspi_done); return IRQ_HANDLED; @@ -1071,7 +1071,7 @@ static irqreturn_t bcm_qspi_bspi_lr_err_l2_isr(int irq, void *dev_id) struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc; dev_err(&qspi->pdev->dev, "BSPI INT error\n"); - qspi->bspi_rf_msg_status = -EIO; + qspi->bspi_rf_op_status = -EIO; if (qspi->soc_intc) /* clear soc interrupt */ soc_intc->bcm_qspi_int_ack(soc_intc, BSPI_ERR); @@ -1194,6 +1194,10 @@ static void bcm_qspi_hw_uninit(struct bcm_qspi *qspi) } +static const struct spi_controller_mem_ops bcm_qspi_mem_ops = { + .exec_op = bcm_qspi_exec_mem_op, +}; + static const struct of_device_id bcm_qspi_of_match[] = { { .compatible = "brcm,spi-bcm-qspi" }, {}, @@ -1236,7 +1240,7 @@ int bcm_qspi_probe(struct platform_device *pdev, master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_RX_DUAL | SPI_RX_QUAD; master->setup = bcm_qspi_setup; master->transfer_one = bcm_qspi_transfer_one; - master->spi_flash_read = bcm_qspi_flash_read; + master->mem_ops = &bcm_qspi_mem_ops; master->cleanup = bcm_qspi_cleanup; master->dev.of_node = dev->of_node; master->num_chipselect = NUM_CHIPSELECT; diff --git a/drivers/spi/spi-bcm53xx.c b/drivers/spi/spi-bcm53xx.c deleted file mode 100644 index d02ceb7a29d1..000000000000 --- a/drivers/spi/spi-bcm53xx.c +++ /dev/null @@ -1,360 +0,0 @@ -/* - * Copyright (C) 2014-2016 RafaÅ‚ MiÅ‚ecki <rafal@milecki.pl> - * - * 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 pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/delay.h> -#include <linux/bcma/bcma.h> -#include <linux/spi/spi.h> - -#include "spi-bcm53xx.h" - -#define BCM53XXSPI_MAX_SPI_BAUD 13500000 /* 216 MHz? */ -#define BCM53XXSPI_FLASH_WINDOW SZ_32M - -/* The longest observed required wait was 19 ms */ -#define BCM53XXSPI_SPE_TIMEOUT_MS 80 - -struct bcm53xxspi { - struct bcma_device *core; - struct spi_master *master; - void __iomem *mmio_base; - bool bspi; /* Boot SPI mode with memory mapping */ -}; - -static inline u32 bcm53xxspi_read(struct bcm53xxspi *b53spi, u16 offset) -{ - return bcma_read32(b53spi->core, offset); -} - -static inline void bcm53xxspi_write(struct bcm53xxspi *b53spi, u16 offset, - u32 value) -{ - bcma_write32(b53spi->core, offset, value); -} - -static void bcm53xxspi_disable_bspi(struct bcm53xxspi *b53spi) -{ - struct device *dev = &b53spi->core->dev; - unsigned long deadline; - u32 tmp; - - if (!b53spi->bspi) - return; - - tmp = bcm53xxspi_read(b53spi, B53SPI_BSPI_MAST_N_BOOT_CTRL); - if (tmp & 0x1) - return; - - deadline = jiffies + usecs_to_jiffies(200); - do { - tmp = bcm53xxspi_read(b53spi, B53SPI_BSPI_BUSY_STATUS); - if (!(tmp & 0x1)) { - bcm53xxspi_write(b53spi, B53SPI_BSPI_MAST_N_BOOT_CTRL, - 0x1); - ndelay(200); - b53spi->bspi = false; - return; - } - udelay(1); - } while (!time_after_eq(jiffies, deadline)); - - dev_warn(dev, "Timeout disabling BSPI\n"); -} - -static void bcm53xxspi_enable_bspi(struct bcm53xxspi *b53spi) -{ - u32 tmp; - - if (b53spi->bspi) - return; - - tmp = bcm53xxspi_read(b53spi, B53SPI_BSPI_MAST_N_BOOT_CTRL); - if (!(tmp & 0x1)) - return; - - bcm53xxspi_write(b53spi, B53SPI_BSPI_MAST_N_BOOT_CTRL, 0x0); - b53spi->bspi = true; -} - -static inline unsigned int bcm53xxspi_calc_timeout(size_t len) -{ - /* Do some magic calculation based on length and buad. Add 10% and 1. */ - return (len * 9000 / BCM53XXSPI_MAX_SPI_BAUD * 110 / 100) + 1; -} - -static int bcm53xxspi_wait(struct bcm53xxspi *b53spi, unsigned int timeout_ms) -{ - unsigned long deadline; - u32 tmp; - - /* SPE bit has to be 0 before we read MSPI STATUS */ - deadline = jiffies + msecs_to_jiffies(BCM53XXSPI_SPE_TIMEOUT_MS); - do { - tmp = bcm53xxspi_read(b53spi, B53SPI_MSPI_SPCR2); - if (!(tmp & B53SPI_MSPI_SPCR2_SPE)) - break; - udelay(5); - } while (!time_after_eq(jiffies, deadline)); - - if (tmp & B53SPI_MSPI_SPCR2_SPE) - goto spi_timeout; - - /* Check status */ - deadline = jiffies + msecs_to_jiffies(timeout_ms); - do { - tmp = bcm53xxspi_read(b53spi, B53SPI_MSPI_MSPI_STATUS); - if (tmp & B53SPI_MSPI_MSPI_STATUS_SPIF) { - bcm53xxspi_write(b53spi, B53SPI_MSPI_MSPI_STATUS, 0); - return 0; - } - - cpu_relax(); - udelay(100); - } while (!time_after_eq(jiffies, deadline)); - -spi_timeout: - bcm53xxspi_write(b53spi, B53SPI_MSPI_MSPI_STATUS, 0); - - pr_err("Timeout waiting for SPI to be ready!\n"); - - return -EBUSY; -} - -static void bcm53xxspi_buf_write(struct bcm53xxspi *b53spi, u8 *w_buf, - size_t len, bool cont) -{ - u32 tmp; - int i; - - for (i = 0; i < len; i++) { - /* Transmit Register File MSB */ - bcm53xxspi_write(b53spi, B53SPI_MSPI_TXRAM + 4 * (i * 2), - (unsigned int)w_buf[i]); - } - - for (i = 0; i < len; i++) { - tmp = B53SPI_CDRAM_CONT | B53SPI_CDRAM_PCS_DISABLE_ALL | - B53SPI_CDRAM_PCS_DSCK; - if (!cont && i == len - 1) - tmp &= ~B53SPI_CDRAM_CONT; - tmp &= ~0x1; - /* Command Register File */ - bcm53xxspi_write(b53spi, B53SPI_MSPI_CDRAM + 4 * i, tmp); - } - - /* Set queue pointers */ - bcm53xxspi_write(b53spi, B53SPI_MSPI_NEWQP, 0); - bcm53xxspi_write(b53spi, B53SPI_MSPI_ENDQP, len - 1); - - if (cont) - bcm53xxspi_write(b53spi, B53SPI_MSPI_WRITE_LOCK, 1); - - /* Start SPI transfer */ - tmp = bcm53xxspi_read(b53spi, B53SPI_MSPI_SPCR2); - tmp |= B53SPI_MSPI_SPCR2_SPE; - if (cont) - tmp |= B53SPI_MSPI_SPCR2_CONT_AFTER_CMD; - bcm53xxspi_write(b53spi, B53SPI_MSPI_SPCR2, tmp); - - /* Wait for SPI to finish */ - bcm53xxspi_wait(b53spi, bcm53xxspi_calc_timeout(len)); - - if (!cont) - bcm53xxspi_write(b53spi, B53SPI_MSPI_WRITE_LOCK, 0); -} - -static void bcm53xxspi_buf_read(struct bcm53xxspi *b53spi, u8 *r_buf, - size_t len, bool cont) -{ - u32 tmp; - int i; - - for (i = 0; i < len; i++) { - tmp = B53SPI_CDRAM_CONT | B53SPI_CDRAM_PCS_DISABLE_ALL | - B53SPI_CDRAM_PCS_DSCK; - if (!cont && i == len - 1) - tmp &= ~B53SPI_CDRAM_CONT; - tmp &= ~0x1; - /* Command Register File */ - bcm53xxspi_write(b53spi, B53SPI_MSPI_CDRAM + 4 * i, tmp); - } - - /* Set queue pointers */ - bcm53xxspi_write(b53spi, B53SPI_MSPI_NEWQP, 0); - bcm53xxspi_write(b53spi, B53SPI_MSPI_ENDQP, len - 1); - - if (cont) - bcm53xxspi_write(b53spi, B53SPI_MSPI_WRITE_LOCK, 1); - - /* Start SPI transfer */ - tmp = bcm53xxspi_read(b53spi, B53SPI_MSPI_SPCR2); - tmp |= B53SPI_MSPI_SPCR2_SPE; - if (cont) - tmp |= B53SPI_MSPI_SPCR2_CONT_AFTER_CMD; - bcm53xxspi_write(b53spi, B53SPI_MSPI_SPCR2, tmp); - - /* Wait for SPI to finish */ - bcm53xxspi_wait(b53spi, bcm53xxspi_calc_timeout(len)); - - if (!cont) - bcm53xxspi_write(b53spi, B53SPI_MSPI_WRITE_LOCK, 0); - - for (i = 0; i < len; ++i) { - u16 reg = B53SPI_MSPI_RXRAM + 4 * (1 + i * 2); - - /* Data stored in the transmit register file LSB */ - r_buf[i] = (u8)bcm53xxspi_read(b53spi, reg); - } -} - -static int bcm53xxspi_transfer_one(struct spi_master *master, - struct spi_device *spi, - struct spi_transfer *t) -{ - struct bcm53xxspi *b53spi = spi_master_get_devdata(master); - u8 *buf; - size_t left; - - bcm53xxspi_disable_bspi(b53spi); - - if (t->tx_buf) { - buf = (u8 *)t->tx_buf; - left = t->len; - while (left) { - size_t to_write = min_t(size_t, 16, left); - bool cont = !spi_transfer_is_last(master, t) || - left - to_write > 0; - - bcm53xxspi_buf_write(b53spi, buf, to_write, cont); - left -= to_write; - buf += to_write; - } - } - - if (t->rx_buf) { - buf = (u8 *)t->rx_buf; - left = t->len; - while (left) { - size_t to_read = min_t(size_t, 16, left); - bool cont = !spi_transfer_is_last(master, t) || - left - to_read > 0; - - bcm53xxspi_buf_read(b53spi, buf, to_read, cont); - left -= to_read; - buf += to_read; - } - } - - return 0; -} - -static int bcm53xxspi_flash_read(struct spi_device *spi, - struct spi_flash_read_message *msg) -{ - struct bcm53xxspi *b53spi = spi_master_get_devdata(spi->master); - int ret = 0; - - if (msg->from + msg->len > BCM53XXSPI_FLASH_WINDOW) - return -EINVAL; - - bcm53xxspi_enable_bspi(b53spi); - memcpy_fromio(msg->buf, b53spi->mmio_base + msg->from, msg->len); - msg->retlen = msg->len; - - return ret; -} - -/************************************************** - * BCMA - **************************************************/ - -static const struct bcma_device_id bcm53xxspi_bcma_tbl[] = { - BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_QSPI, BCMA_ANY_REV, BCMA_ANY_CLASS), - {}, -}; -MODULE_DEVICE_TABLE(bcma, bcm53xxspi_bcma_tbl); - -static int bcm53xxspi_bcma_probe(struct bcma_device *core) -{ - struct device *dev = &core->dev; - struct bcm53xxspi *b53spi; - struct spi_master *master; - int err; - - if (core->bus->drv_cc.core->id.rev != 42) { - pr_err("SPI on SoC with unsupported ChipCommon rev\n"); - return -ENOTSUPP; - } - - master = spi_alloc_master(dev, sizeof(*b53spi)); - if (!master) - return -ENOMEM; - - b53spi = spi_master_get_devdata(master); - b53spi->master = master; - b53spi->core = core; - - if (core->addr_s[0]) - b53spi->mmio_base = devm_ioremap(dev, core->addr_s[0], - BCM53XXSPI_FLASH_WINDOW); - b53spi->bspi = true; - bcm53xxspi_disable_bspi(b53spi); - - master->dev.of_node = dev->of_node; - master->transfer_one = bcm53xxspi_transfer_one; - if (b53spi->mmio_base) - master->spi_flash_read = bcm53xxspi_flash_read; - - bcma_set_drvdata(core, b53spi); - - err = devm_spi_register_master(dev, master); - if (err) { - spi_master_put(master); - bcma_set_drvdata(core, NULL); - return err; - } - - return 0; -} - -static struct bcma_driver bcm53xxspi_bcma_driver = { - .name = KBUILD_MODNAME, - .id_table = bcm53xxspi_bcma_tbl, - .probe = bcm53xxspi_bcma_probe, -}; - -/************************************************** - * Init & exit - **************************************************/ - -static int __init bcm53xxspi_module_init(void) -{ - int err = 0; - - err = bcma_driver_register(&bcm53xxspi_bcma_driver); - if (err) - pr_err("Failed to register bcma driver: %d\n", err); - - return err; -} - -static void __exit bcm53xxspi_module_exit(void) -{ - bcma_driver_unregister(&bcm53xxspi_bcma_driver); -} - -module_init(bcm53xxspi_module_init); -module_exit(bcm53xxspi_module_exit); - -MODULE_DESCRIPTION("Broadcom BCM53xx SPI Controller driver"); -MODULE_AUTHOR("RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com>"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/spi/spi-bcm53xx.h b/drivers/spi/spi-bcm53xx.h deleted file mode 100644 index 03e3442086ec..000000000000 --- a/drivers/spi/spi-bcm53xx.h +++ /dev/null @@ -1,73 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef SPI_BCM53XX_H -#define SPI_BCM53XX_H - -#define B53SPI_BSPI_REVISION_ID 0x000 -#define B53SPI_BSPI_SCRATCH 0x004 -#define B53SPI_BSPI_MAST_N_BOOT_CTRL 0x008 -#define B53SPI_BSPI_BUSY_STATUS 0x00c -#define B53SPI_BSPI_INTR_STATUS 0x010 -#define B53SPI_BSPI_B0_STATUS 0x014 -#define B53SPI_BSPI_B0_CTRL 0x018 -#define B53SPI_BSPI_B1_STATUS 0x01c -#define B53SPI_BSPI_B1_CTRL 0x020 -#define B53SPI_BSPI_STRAP_OVERRIDE_CTRL 0x024 -#define B53SPI_BSPI_FLEX_MODE_ENABLE 0x028 -#define B53SPI_BSPI_BITS_PER_CYCLE 0x02c -#define B53SPI_BSPI_BITS_PER_PHASE 0x030 -#define B53SPI_BSPI_CMD_AND_MODE_BYTE 0x034 -#define B53SPI_BSPI_BSPI_FLASH_UPPER_ADDR_BYTE 0x038 -#define B53SPI_BSPI_BSPI_XOR_VALUE 0x03c -#define B53SPI_BSPI_BSPI_XOR_ENABLE 0x040 -#define B53SPI_BSPI_BSPI_PIO_MODE_ENABLE 0x044 -#define B53SPI_BSPI_BSPI_PIO_IODIR 0x048 -#define B53SPI_BSPI_BSPI_PIO_DATA 0x04c - -/* RAF */ -#define B53SPI_RAF_START_ADDR 0x100 -#define B53SPI_RAF_NUM_WORDS 0x104 -#define B53SPI_RAF_CTRL 0x108 -#define B53SPI_RAF_FULLNESS 0x10c -#define B53SPI_RAF_WATERMARK 0x110 -#define B53SPI_RAF_STATUS 0x114 -#define B53SPI_RAF_READ_DATA 0x118 -#define B53SPI_RAF_WORD_CNT 0x11c -#define B53SPI_RAF_CURR_ADDR 0x120 - -/* MSPI */ -#define B53SPI_MSPI_SPCR0_LSB 0x200 -#define B53SPI_MSPI_SPCR0_MSB 0x204 -#define B53SPI_MSPI_SPCR1_LSB 0x208 -#define B53SPI_MSPI_SPCR1_MSB 0x20c -#define B53SPI_MSPI_NEWQP 0x210 -#define B53SPI_MSPI_ENDQP 0x214 -#define B53SPI_MSPI_SPCR2 0x218 -#define B53SPI_MSPI_SPCR2_SPE 0x00000040 -#define B53SPI_MSPI_SPCR2_CONT_AFTER_CMD 0x00000080 -#define B53SPI_MSPI_MSPI_STATUS 0x220 -#define B53SPI_MSPI_MSPI_STATUS_SPIF 0x00000001 -#define B53SPI_MSPI_CPTQP 0x224 -#define B53SPI_MSPI_TXRAM 0x240 /* 32 registers, up to 0x2b8 */ -#define B53SPI_MSPI_RXRAM 0x2c0 /* 32 registers, up to 0x33c */ -#define B53SPI_MSPI_CDRAM 0x340 /* 16 registers, up to 0x37c */ -#define B53SPI_CDRAM_PCS_PCS0 0x00000001 -#define B53SPI_CDRAM_PCS_PCS1 0x00000002 -#define B53SPI_CDRAM_PCS_PCS2 0x00000004 -#define B53SPI_CDRAM_PCS_PCS3 0x00000008 -#define B53SPI_CDRAM_PCS_DISABLE_ALL 0x0000000f -#define B53SPI_CDRAM_PCS_DSCK 0x00000010 -#define B53SPI_CDRAM_BITSE 0x00000040 -#define B53SPI_CDRAM_CONT 0x00000080 -#define B53SPI_MSPI_WRITE_LOCK 0x380 -#define B53SPI_MSPI_DISABLE_FLUSH_GEN 0x384 - -/* Interrupt */ -#define B53SPI_INTR_RAF_LR_FULLNESS_REACHED 0x3a0 -#define B53SPI_INTR_RAF_LR_TRUNCATED 0x3a4 -#define B53SPI_INTR_RAF_LR_IMPATIENT 0x3a8 -#define B53SPI_INTR_RAF_LR_SESSION_DONE 0x3ac -#define B53SPI_INTR_RAF_LR_OVERREAD 0x3b0 -#define B53SPI_INTR_MSPI_DONE 0x3b4 -#define B53SPI_INTR_MSPI_HALT_SET_TRANSACTION_DONE 0x3b8 - -#endif /* SPI_BCM53XX_H */ diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c index cbcba614b253..c23849f7aa7b 100644 --- a/drivers/spi/spi-bcm63xx-hsspi.c +++ b/drivers/spi/spi-bcm63xx-hsspi.c @@ -352,22 +352,31 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev) if (IS_ERR(clk)) return PTR_ERR(clk); + ret = clk_prepare_enable(clk); + if (ret) + return ret; + rate = clk_get_rate(clk); if (!rate) { struct clk *pll_clk = devm_clk_get(dev, "pll"); - if (IS_ERR(pll_clk)) - return PTR_ERR(pll_clk); + if (IS_ERR(pll_clk)) { + ret = PTR_ERR(pll_clk); + goto out_disable_clk; + } + + ret = clk_prepare_enable(pll_clk); + if (ret) + goto out_disable_clk; rate = clk_get_rate(pll_clk); - if (!rate) - return -EINVAL; + clk_disable_unprepare(pll_clk); + if (!rate) { + ret = -EINVAL; + goto out_disable_clk; + } } - ret = clk_prepare_enable(clk); - if (ret) - return ret; - master = spi_alloc_master(&pdev->dev, sizeof(*bs)); if (!master) { ret = -ENOMEM; diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c index 4a001634023e..f3dad6fcdc35 100644 --- a/drivers/spi/spi-cadence.c +++ b/drivers/spi/spi-cadence.c @@ -694,8 +694,7 @@ static int cdns_spi_remove(struct platform_device *pdev) */ static int __maybe_unused cdns_spi_suspend(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct spi_master *master = platform_get_drvdata(pdev); + struct spi_master *master = dev_get_drvdata(dev); return spi_master_suspend(master); } @@ -710,8 +709,7 @@ static int __maybe_unused cdns_spi_suspend(struct device *dev) */ static int __maybe_unused cdns_spi_resume(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct spi_master *master = platform_get_drvdata(pdev); + struct spi_master *master = dev_get_drvdata(dev); struct cdns_spi *xspi = spi_master_get_devdata(master); cdns_spi_init_hw(xspi); diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index cb3c73007ca1..e6d5cc6ab108 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -1,19 +1,8 @@ -/* - * Freescale i.MX7ULP LPSPI driver - * - * Copyright 2016 Freescale Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// Freescale i.MX7ULP LPSPI driver +// +// Copyright 2016 Freescale Semiconductor, Inc. #include <linux/clk.h> #include <linux/completion.h> diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index a056ee88a960..866246f21041 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -1,22 +1,6 @@ -/* - * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. - * Copyright (C) 2008 Juergen Beisert - * - * 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 - * 51 Franklin Street, Fifth Floor - * Boston, MA 02110-1301, USA. - */ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. +// Copyright (C) 2008 Juergen Beisert #include <linux/clk.h> #include <linux/completion.h> diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c new file mode 100644 index 000000000000..990770dfa5cf --- /dev/null +++ b/drivers/spi/spi-mem.c @@ -0,0 +1,410 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018 Exceet Electronics GmbH + * Copyright (C) 2018 Bootlin + * + * Author: Boris Brezillon <boris.brezillon@bootlin.com> + */ +#include <linux/dmaengine.h> +#include <linux/pm_runtime.h> +#include <linux/spi/spi.h> +#include <linux/spi/spi-mem.h> + +#include "internals.h" + +/** + * spi_controller_dma_map_mem_op_data() - DMA-map the buffer attached to a + * memory operation + * @ctlr: the SPI controller requesting this dma_map() + * @op: the memory operation containing the buffer to map + * @sgt: a pointer to a non-initialized sg_table that will be filled by this + * function + * + * Some controllers might want to do DMA on the data buffer embedded in @op. + * This helper prepares everything for you and provides a ready-to-use + * sg_table. This function is not intended to be called from spi drivers. + * Only SPI controller drivers should use it. + * Note that the caller must ensure the memory region pointed by + * op->data.buf.{in,out} is DMA-able before calling this function. + * + * Return: 0 in case of success, a negative error code otherwise. + */ +int spi_controller_dma_map_mem_op_data(struct spi_controller *ctlr, + const struct spi_mem_op *op, + struct sg_table *sgt) +{ + struct device *dmadev; + + if (!op->data.nbytes) + return -EINVAL; + + if (op->data.dir == SPI_MEM_DATA_OUT && ctlr->dma_tx) + dmadev = ctlr->dma_tx->device->dev; + else if (op->data.dir == SPI_MEM_DATA_IN && ctlr->dma_rx) + dmadev = ctlr->dma_rx->device->dev; + else + dmadev = ctlr->dev.parent; + + if (!dmadev) + return -EINVAL; + + return spi_map_buf(ctlr, dmadev, sgt, op->data.buf.in, op->data.nbytes, + op->data.dir == SPI_MEM_DATA_IN ? + DMA_FROM_DEVICE : DMA_TO_DEVICE); +} +EXPORT_SYMBOL_GPL(spi_controller_dma_map_mem_op_data); + +/** + * spi_controller_dma_unmap_mem_op_data() - DMA-unmap the buffer attached to a + * memory operation + * @ctlr: the SPI controller requesting this dma_unmap() + * @op: the memory operation containing the buffer to unmap + * @sgt: a pointer to an sg_table previously initialized by + * spi_controller_dma_map_mem_op_data() + * + * Some controllers might want to do DMA on the data buffer embedded in @op. + * This helper prepares things so that the CPU can access the + * op->data.buf.{in,out} buffer again. + * + * This function is not intended to be called from SPI drivers. Only SPI + * controller drivers should use it. + * + * This function should be called after the DMA operation has finished and is + * only valid if the previous spi_controller_dma_map_mem_op_data() call + * returned 0. + * + * Return: 0 in case of success, a negative error code otherwise. + */ +void spi_controller_dma_unmap_mem_op_data(struct spi_controller *ctlr, + const struct spi_mem_op *op, + struct sg_table *sgt) +{ + struct device *dmadev; + + if (!op->data.nbytes) + return; + + if (op->data.dir == SPI_MEM_DATA_OUT && ctlr->dma_tx) + dmadev = ctlr->dma_tx->device->dev; + else if (op->data.dir == SPI_MEM_DATA_IN && ctlr->dma_rx) + dmadev = ctlr->dma_rx->device->dev; + else + dmadev = ctlr->dev.parent; + + spi_unmap_buf(ctlr, dmadev, sgt, + op->data.dir == SPI_MEM_DATA_IN ? + DMA_FROM_DEVICE : DMA_TO_DEVICE); +} +EXPORT_SYMBOL_GPL(spi_controller_dma_unmap_mem_op_data); + +static int spi_check_buswidth_req(struct spi_mem *mem, u8 buswidth, bool tx) +{ + u32 mode = mem->spi->mode; + + switch (buswidth) { + case 1: + return 0; + + case 2: + if ((tx && (mode & (SPI_TX_DUAL | SPI_TX_QUAD))) || + (!tx && (mode & (SPI_RX_DUAL | SPI_RX_QUAD)))) + return 0; + + break; + + case 4: + if ((tx && (mode & SPI_TX_QUAD)) || + (!tx && (mode & SPI_RX_QUAD))) + return 0; + + break; + + default: + break; + } + + return -ENOTSUPP; +} + +static bool spi_mem_default_supports_op(struct spi_mem *mem, + const struct spi_mem_op *op) +{ + if (spi_check_buswidth_req(mem, op->cmd.buswidth, true)) + return false; + + if (op->addr.nbytes && + spi_check_buswidth_req(mem, op->addr.buswidth, true)) + return false; + + if (op->dummy.nbytes && + spi_check_buswidth_req(mem, op->dummy.buswidth, true)) + return false; + + if (op->data.nbytes && + spi_check_buswidth_req(mem, op->data.buswidth, + op->data.dir == SPI_MEM_DATA_OUT)) + return false; + + return true; +} +EXPORT_SYMBOL_GPL(spi_mem_default_supports_op); + +/** + * spi_mem_supports_op() - Check if a memory device and the controller it is + * connected to support a specific memory operation + * @mem: the SPI memory + * @op: the memory operation to check + * + * Some controllers are only supporting Single or Dual IOs, others might only + * support specific opcodes, or it can even be that the controller and device + * both support Quad IOs but the hardware prevents you from using it because + * only 2 IO lines are connected. + * + * This function checks whether a specific operation is supported. + * + * Return: true if @op is supported, false otherwise. + */ +bool spi_mem_supports_op(struct spi_mem *mem, const struct spi_mem_op *op) +{ + struct spi_controller *ctlr = mem->spi->controller; + + if (ctlr->mem_ops && ctlr->mem_ops->supports_op) + return ctlr->mem_ops->supports_op(mem, op); + + return spi_mem_default_supports_op(mem, op); +} +EXPORT_SYMBOL_GPL(spi_mem_supports_op); + +/** + * spi_mem_exec_op() - Execute a memory operation + * @mem: the SPI memory + * @op: the memory operation to execute + * + * Executes a memory operation. + * + * This function first checks that @op is supported and then tries to execute + * it. + * + * Return: 0 in case of success, a negative error code otherwise. + */ +int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) +{ + unsigned int tmpbufsize, xferpos = 0, totalxferlen = 0; + struct spi_controller *ctlr = mem->spi->controller; + struct spi_transfer xfers[4] = { }; + struct spi_message msg; + u8 *tmpbuf; + int ret; + + if (!spi_mem_supports_op(mem, op)) + return -ENOTSUPP; + + if (ctlr->mem_ops) { + /* + * Flush the message queue before executing our SPI memory + * operation to prevent preemption of regular SPI transfers. + */ + spi_flush_queue(ctlr); + + if (ctlr->auto_runtime_pm) { + ret = pm_runtime_get_sync(ctlr->dev.parent); + if (ret < 0) { + dev_err(&ctlr->dev, + "Failed to power device: %d\n", + ret); + return ret; + } + } + + mutex_lock(&ctlr->bus_lock_mutex); + mutex_lock(&ctlr->io_mutex); + ret = ctlr->mem_ops->exec_op(mem, op); + mutex_unlock(&ctlr->io_mutex); + mutex_unlock(&ctlr->bus_lock_mutex); + + if (ctlr->auto_runtime_pm) + pm_runtime_put(ctlr->dev.parent); + + /* + * Some controllers only optimize specific paths (typically the + * read path) and expect the core to use the regular SPI + * interface in other cases. + */ + if (!ret || ret != -ENOTSUPP) + return ret; + } + + tmpbufsize = sizeof(op->cmd.opcode) + op->addr.nbytes + + op->dummy.nbytes; + + /* + * Allocate a buffer to transmit the CMD, ADDR cycles with kmalloc() so + * we're guaranteed that this buffer is DMA-able, as required by the + * SPI layer. + */ + tmpbuf = kzalloc(tmpbufsize, GFP_KERNEL | GFP_DMA); + if (!tmpbuf) + return -ENOMEM; + + spi_message_init(&msg); + + tmpbuf[0] = op->cmd.opcode; + xfers[xferpos].tx_buf = tmpbuf; + xfers[xferpos].len = sizeof(op->cmd.opcode); + xfers[xferpos].tx_nbits = op->cmd.buswidth; + spi_message_add_tail(&xfers[xferpos], &msg); + xferpos++; + totalxferlen++; + + if (op->addr.nbytes) { + int i; + + for (i = 0; i < op->addr.nbytes; i++) + tmpbuf[i + 1] = op->addr.val >> + (8 * (op->addr.nbytes - i - 1)); + + xfers[xferpos].tx_buf = tmpbuf + 1; + xfers[xferpos].len = op->addr.nbytes; + xfers[xferpos].tx_nbits = op->addr.buswidth; + spi_message_add_tail(&xfers[xferpos], &msg); + xferpos++; + totalxferlen += op->addr.nbytes; + } + + if (op->dummy.nbytes) { + memset(tmpbuf + op->addr.nbytes + 1, 0xff, op->dummy.nbytes); + xfers[xferpos].tx_buf = tmpbuf + op->addr.nbytes + 1; + xfers[xferpos].len = op->dummy.nbytes; + xfers[xferpos].tx_nbits = op->dummy.buswidth; + spi_message_add_tail(&xfers[xferpos], &msg); + xferpos++; + totalxferlen += op->dummy.nbytes; + } + + if (op->data.nbytes) { + if (op->data.dir == SPI_MEM_DATA_IN) { + xfers[xferpos].rx_buf = op->data.buf.in; + xfers[xferpos].rx_nbits = op->data.buswidth; + } else { + xfers[xferpos].tx_buf = op->data.buf.out; + xfers[xferpos].tx_nbits = op->data.buswidth; + } + + xfers[xferpos].len = op->data.nbytes; + spi_message_add_tail(&xfers[xferpos], &msg); + xferpos++; + totalxferlen += op->data.nbytes; + } + + ret = spi_sync(mem->spi, &msg); + + kfree(tmpbuf); + + if (ret) + return ret; + + if (msg.actual_length != totalxferlen) + return -EIO; + + return 0; +} +EXPORT_SYMBOL_GPL(spi_mem_exec_op); + +/** + * spi_mem_adjust_op_size() - Adjust the data size of a SPI mem operation to + * match controller limitations + * @mem: the SPI memory + * @op: the operation to adjust + * + * Some controllers have FIFO limitations and must split a data transfer + * operation into multiple ones, others require a specific alignment for + * optimized accesses. This function allows SPI mem drivers to split a single + * operation into multiple sub-operations when required. + * + * Return: a negative error code if the controller can't properly adjust @op, + * 0 otherwise. Note that @op->data.nbytes will be updated if @op + * can't be handled in a single step. + */ +int spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op) +{ + struct spi_controller *ctlr = mem->spi->controller; + + if (ctlr->mem_ops && ctlr->mem_ops->adjust_op_size) + return ctlr->mem_ops->adjust_op_size(mem, op); + + return 0; +} +EXPORT_SYMBOL_GPL(spi_mem_adjust_op_size); + +static inline struct spi_mem_driver *to_spi_mem_drv(struct device_driver *drv) +{ + return container_of(drv, struct spi_mem_driver, spidrv.driver); +} + +static int spi_mem_probe(struct spi_device *spi) +{ + struct spi_mem_driver *memdrv = to_spi_mem_drv(spi->dev.driver); + struct spi_mem *mem; + + mem = devm_kzalloc(&spi->dev, sizeof(*mem), GFP_KERNEL); + if (!mem) + return -ENOMEM; + + mem->spi = spi; + spi_set_drvdata(spi, mem); + + return memdrv->probe(mem); +} + +static int spi_mem_remove(struct spi_device *spi) +{ + struct spi_mem_driver *memdrv = to_spi_mem_drv(spi->dev.driver); + struct spi_mem *mem = spi_get_drvdata(spi); + + if (memdrv->remove) + return memdrv->remove(mem); + + return 0; +} + +static void spi_mem_shutdown(struct spi_device *spi) +{ + struct spi_mem_driver *memdrv = to_spi_mem_drv(spi->dev.driver); + struct spi_mem *mem = spi_get_drvdata(spi); + + if (memdrv->shutdown) + memdrv->shutdown(mem); +} + +/** + * spi_mem_driver_register_with_owner() - Register a SPI memory driver + * @memdrv: the SPI memory driver to register + * @owner: the owner of this driver + * + * Registers a SPI memory driver. + * + * Return: 0 in case of success, a negative error core otherwise. + */ + +int spi_mem_driver_register_with_owner(struct spi_mem_driver *memdrv, + struct module *owner) +{ + memdrv->spidrv.probe = spi_mem_probe; + memdrv->spidrv.remove = spi_mem_remove; + memdrv->spidrv.shutdown = spi_mem_shutdown; + + return __spi_register_driver(owner, &memdrv->spidrv); +} +EXPORT_SYMBOL_GPL(spi_mem_driver_register_with_owner); + +/** + * spi_mem_driver_unregister_with_owner() - Unregister a SPI memory driver + * @memdrv: the SPI memory driver to unregister + * + * Unregisters a SPI memory driver. + */ +void spi_mem_driver_unregister(struct spi_mem_driver *memdrv) +{ + spi_unregister_driver(&memdrv->spidrv); +} +EXPORT_SYMBOL_GPL(spi_mem_driver_unregister); diff --git a/drivers/spi/spi-meson-spicc.c b/drivers/spi/spi-meson-spicc.c index 5c82910e3480..7fe4488ace57 100644 --- a/drivers/spi/spi-meson-spicc.c +++ b/drivers/spi/spi-meson-spicc.c @@ -574,10 +574,15 @@ static int meson_spicc_probe(struct platform_device *pdev) master->max_speed_hz = rate >> 2; ret = devm_spi_register_master(&pdev->dev, master); - if (!ret) - return 0; + if (ret) { + dev_err(&pdev->dev, "spi master registration failed\n"); + goto out_clk; + } - dev_err(&pdev->dev, "spi master registration failed\n"); + return 0; + +out_clk: + clk_disable_unprepare(spicc->core); out_master: spi_master_put(master); diff --git a/drivers/spi/spi-mpc52xx.c b/drivers/spi/spi-mpc52xx.c index e8b59ce4dc3a..0e55784a3ad9 100644 --- a/drivers/spi/spi-mpc52xx.c +++ b/drivers/spi/spi-mpc52xx.c @@ -447,7 +447,7 @@ static int mpc52xx_spi_probe(struct platform_device *op) for (i = 0; i < ms->gpio_cs_count; i++) { gpio_cs = of_get_gpio(op->dev.of_node, i); - if (gpio_cs < 0) { + if (!gpio_is_valid(gpio_cs)) { dev_err(&op->dev, "could not parse the gpio field in oftree\n"); rc = -ENODEV; diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c index 3d216b950b41..6ac95a2a21ce 100644 --- a/drivers/spi/spi-mxs.c +++ b/drivers/spi/spi-mxs.c @@ -1,32 +1,22 @@ -/* - * Freescale MXS SPI master driver - * - * Copyright 2012 DENX Software Engineering, GmbH. - * Copyright 2012 Freescale Semiconductor, Inc. - * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. - * - * Rework and transition to new API by: - * Marek Vasut <marex@denx.de> - * - * Based on previous attempt by: - * Fabio Estevam <fabio.estevam@freescale.com> - * - * Based on code from U-Boot bootloader by: - * Marek Vasut <marex@denx.de> - * - * Based on spi-stmp.c, which is: - * Author: Dmitry Pervushin <dimka@embeddedalley.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. - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// Freescale MXS SPI master driver +// +// Copyright 2012 DENX Software Engineering, GmbH. +// Copyright 2012 Freescale Semiconductor, Inc. +// Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. +// +// Rework and transition to new API by: +// Marek Vasut <marex@denx.de> +// +// Based on previous attempt by: +// Fabio Estevam <fabio.estevam@freescale.com> +// +// Based on code from U-Boot bootloader by: +// Marek Vasut <marex@denx.de> +// +// Based on spi-stmp.c, which is: +// Author: Dmitry Pervushin <dimka@embeddedalley.com> #include <linux/kernel.h> #include <linux/ioport.h> diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 9bf64e6eca9b..6c628a54e946 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -255,6 +255,7 @@ static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable) if (spi->controller_state) { int err = pm_runtime_get_sync(mcspi->dev); if (err < 0) { + pm_runtime_put_noidle(mcspi->dev); dev_err(mcspi->dev, "failed to get sync: %d\n", err); return; } @@ -350,20 +351,6 @@ disable_fifo: mcspi->fifo_depth = 0; } -static void omap2_mcspi_restore_ctx(struct omap2_mcspi *mcspi) -{ - struct spi_master *spi_cntrl = mcspi->master; - struct omap2_mcspi_regs *ctx = &mcspi->ctx; - struct omap2_mcspi_cs *cs; - - /* McSPI: context restore */ - mcspi_write_reg(spi_cntrl, OMAP2_MCSPI_MODULCTRL, ctx->modulctrl); - mcspi_write_reg(spi_cntrl, OMAP2_MCSPI_WAKEUPENABLE, ctx->wakeupenable); - - list_for_each_entry(cs, &ctx->cs, node) - writel_relaxed(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0); -} - static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit) { unsigned long timeout; @@ -1065,8 +1052,11 @@ static int omap2_mcspi_setup(struct spi_device *spi) } ret = pm_runtime_get_sync(mcspi->dev); - if (ret < 0) + if (ret < 0) { + pm_runtime_put_noidle(mcspi->dev); + return ret; + } ret = omap2_mcspi_setup_transfer(spi, NULL); pm_runtime_mark_last_busy(mcspi->dev); @@ -1284,8 +1274,11 @@ static int omap2_mcspi_master_setup(struct omap2_mcspi *mcspi) int ret = 0; ret = pm_runtime_get_sync(mcspi->dev); - if (ret < 0) + if (ret < 0) { + pm_runtime_put_noidle(mcspi->dev); + return ret; + } mcspi_write_reg(master, OMAP2_MCSPI_WAKEUPENABLE, OMAP2_MCSPI_WAKEUPENABLE_WKEN); @@ -1297,14 +1290,39 @@ static int omap2_mcspi_master_setup(struct omap2_mcspi *mcspi) return 0; } +/* + * When SPI wake up from off-mode, CS is in activate state. If it was in + * inactive state when driver was suspend, then force it to inactive state at + * wake up. + */ static int omap_mcspi_runtime_resume(struct device *dev) { - struct omap2_mcspi *mcspi; - struct spi_master *master; + struct spi_master *master = dev_get_drvdata(dev); + struct omap2_mcspi *mcspi = spi_master_get_devdata(master); + struct omap2_mcspi_regs *ctx = &mcspi->ctx; + struct omap2_mcspi_cs *cs; - master = dev_get_drvdata(dev); - mcspi = spi_master_get_devdata(master); - omap2_mcspi_restore_ctx(mcspi); + /* McSPI: context restore */ + mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, ctx->modulctrl); + mcspi_write_reg(master, OMAP2_MCSPI_WAKEUPENABLE, ctx->wakeupenable); + + list_for_each_entry(cs, &ctx->cs, node) { + /* + * We need to toggle CS state for OMAP take this + * change in account. + */ + if ((cs->chconf0 & OMAP2_MCSPI_CHCONF_FORCE) == 0) { + cs->chconf0 |= OMAP2_MCSPI_CHCONF_FORCE; + writel_relaxed(cs->chconf0, + cs->base + OMAP2_MCSPI_CHCONF0); + cs->chconf0 &= ~OMAP2_MCSPI_CHCONF_FORCE; + writel_relaxed(cs->chconf0, + cs->base + OMAP2_MCSPI_CHCONF0); + } else { + writel_relaxed(cs->chconf0, + cs->base + OMAP2_MCSPI_CHCONF0); + } + } return 0; } @@ -1447,50 +1465,33 @@ static int omap2_mcspi_remove(struct platform_device *pdev) MODULE_ALIAS("platform:omap2_mcspi"); #ifdef CONFIG_SUSPEND -/* - * When SPI wake up from off-mode, CS is in activate state. If it was in - * unactive state when driver was suspend, then force it to unactive state at - * wake up. - */ -static int omap2_mcspi_resume(struct device *dev) +static int omap2_mcspi_suspend_noirq(struct device *dev) { - struct spi_master *master = dev_get_drvdata(dev); - struct omap2_mcspi *mcspi = spi_master_get_devdata(master); - struct omap2_mcspi_regs *ctx = &mcspi->ctx; - struct omap2_mcspi_cs *cs; - - pm_runtime_get_sync(mcspi->dev); - list_for_each_entry(cs, &ctx->cs, node) { - if ((cs->chconf0 & OMAP2_MCSPI_CHCONF_FORCE) == 0) { - /* - * We need to toggle CS state for OMAP take this - * change in account. - */ - cs->chconf0 |= OMAP2_MCSPI_CHCONF_FORCE; - writel_relaxed(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0); - cs->chconf0 &= ~OMAP2_MCSPI_CHCONF_FORCE; - writel_relaxed(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0); - } - } - pm_runtime_mark_last_busy(mcspi->dev); - pm_runtime_put_autosuspend(mcspi->dev); - - return pinctrl_pm_select_default_state(dev); + return pinctrl_pm_select_sleep_state(dev); } -static int omap2_mcspi_suspend(struct device *dev) +static int omap2_mcspi_resume_noirq(struct device *dev) { - return pinctrl_pm_select_sleep_state(dev); + struct spi_master *master = dev_get_drvdata(dev); + struct omap2_mcspi *mcspi = spi_master_get_devdata(master); + int error; + + error = pinctrl_pm_select_default_state(dev); + if (error) + dev_warn(mcspi->dev, "%s: failed to set pins: %i\n", + __func__, error); + + return 0; } #else -#define omap2_mcspi_suspend NULL -#define omap2_mcspi_resume NULL +#define omap2_mcspi_suspend_noirq NULL +#define omap2_mcspi_resume_noirq NULL #endif static const struct dev_pm_ops omap2_mcspi_pm_ops = { - .resume = omap2_mcspi_resume, - .suspend = omap2_mcspi_suspend, + .suspend_noirq = omap2_mcspi_suspend_noirq, + .resume_noirq = omap2_mcspi_resume_noirq, .runtime_resume = omap_mcspi_runtime_resume, }; diff --git a/drivers/spi/spi-pxa2xx-dma.c b/drivers/spi/spi-pxa2xx-dma.c index 3d7f66080c57..2fa7f4b43492 100644 --- a/drivers/spi/spi-pxa2xx-dma.c +++ b/drivers/spi/spi-pxa2xx-dma.c @@ -51,19 +51,15 @@ static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data, if (!pxa25x_ssp_comp(drv_data)) pxa2xx_spi_write(drv_data, SSTO, 0); - if (!error) { - msg->actual_length += drv_data->len; - msg->state = pxa2xx_spi_next_transfer(drv_data); - } else { + if (error) { /* In case we got an error we disable the SSP now */ pxa2xx_spi_write(drv_data, SSCR0, pxa2xx_spi_read(drv_data, SSCR0) & ~SSCR0_SSE); - - msg->state = ERROR_STATE; + msg->status = -EIO; } - tasklet_schedule(&drv_data->pump_transfers); + spi_finalize_current_transfer(drv_data->master); } } @@ -74,11 +70,11 @@ static void pxa2xx_spi_dma_callback(void *data) static struct dma_async_tx_descriptor * pxa2xx_spi_dma_prepare_one(struct driver_data *drv_data, - enum dma_transfer_direction dir) + enum dma_transfer_direction dir, + struct spi_transfer *xfer) { struct chip_data *chip = spi_get_ctldata(drv_data->master->cur_msg->spi); - struct spi_transfer *xfer = drv_data->cur_transfer; enum dma_slave_buswidth width; struct dma_slave_config cfg; struct dma_chan *chan; @@ -144,12 +140,13 @@ irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data) return IRQ_NONE; } -int pxa2xx_spi_dma_prepare(struct driver_data *drv_data, u32 dma_burst) +int pxa2xx_spi_dma_prepare(struct driver_data *drv_data, + struct spi_transfer *xfer) { struct dma_async_tx_descriptor *tx_desc, *rx_desc; int err; - tx_desc = pxa2xx_spi_dma_prepare_one(drv_data, DMA_MEM_TO_DEV); + tx_desc = pxa2xx_spi_dma_prepare_one(drv_data, DMA_MEM_TO_DEV, xfer); if (!tx_desc) { dev_err(&drv_data->pdev->dev, "failed to get DMA TX descriptor\n"); @@ -157,7 +154,7 @@ int pxa2xx_spi_dma_prepare(struct driver_data *drv_data, u32 dma_burst) goto err_tx; } - rx_desc = pxa2xx_spi_dma_prepare_one(drv_data, DMA_DEV_TO_MEM); + rx_desc = pxa2xx_spi_dma_prepare_one(drv_data, DMA_DEV_TO_MEM, xfer); if (!rx_desc) { dev_err(&drv_data->pdev->dev, "failed to get DMA RX descriptor\n"); @@ -187,6 +184,13 @@ void pxa2xx_spi_dma_start(struct driver_data *drv_data) atomic_set(&drv_data->dma_running, 1); } +void pxa2xx_spi_dma_stop(struct driver_data *drv_data) +{ + atomic_set(&drv_data->dma_running, 0); + dmaengine_terminate_sync(drv_data->master->dma_rx); + dmaengine_terminate_sync(drv_data->master->dma_tx); +} + int pxa2xx_spi_dma_setup(struct driver_data *drv_data) { struct pxa2xx_spi_master *pdata = drv_data->master_info; diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 82dcb88fcfba..0b2d60d30f69 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -340,9 +340,11 @@ static void lpss_ssp_setup(struct driver_data *drv_data) } } -static void lpss_ssp_select_cs(struct driver_data *drv_data, +static void lpss_ssp_select_cs(struct spi_device *spi, const struct lpss_config *config) { + struct driver_data *drv_data = + spi_controller_get_devdata(spi->controller); u32 value, cs; if (!config->cs_sel_mask) @@ -350,7 +352,7 @@ static void lpss_ssp_select_cs(struct driver_data *drv_data, value = __lpss_ssp_read_priv(drv_data, config->reg_cs_ctrl); - cs = drv_data->master->cur_msg->spi->chip_select; + cs = spi->chip_select; cs <<= config->cs_sel_shift; if (cs != (value & config->cs_sel_mask)) { /* @@ -369,15 +371,17 @@ static void lpss_ssp_select_cs(struct driver_data *drv_data, } } -static void lpss_ssp_cs_control(struct driver_data *drv_data, bool enable) +static void lpss_ssp_cs_control(struct spi_device *spi, bool enable) { + struct driver_data *drv_data = + spi_controller_get_devdata(spi->controller); const struct lpss_config *config; u32 value; config = lpss_get_config(drv_data); if (enable) - lpss_ssp_select_cs(drv_data, config); + lpss_ssp_select_cs(spi, config); value = __lpss_ssp_read_priv(drv_data, config->reg_cs_ctrl); if (enable) @@ -387,10 +391,11 @@ static void lpss_ssp_cs_control(struct driver_data *drv_data, bool enable) __lpss_ssp_write_priv(drv_data, config->reg_cs_ctrl, value); } -static void cs_assert(struct driver_data *drv_data) +static void cs_assert(struct spi_device *spi) { - struct chip_data *chip = - spi_get_ctldata(drv_data->master->cur_msg->spi); + struct chip_data *chip = spi_get_ctldata(spi); + struct driver_data *drv_data = + spi_controller_get_devdata(spi->controller); if (drv_data->ssp_type == CE4100_SSP) { pxa2xx_spi_write(drv_data, SSSR, chip->frm); @@ -408,13 +413,14 @@ static void cs_assert(struct driver_data *drv_data) } if (is_lpss_ssp(drv_data)) - lpss_ssp_cs_control(drv_data, true); + lpss_ssp_cs_control(spi, true); } -static void cs_deassert(struct driver_data *drv_data) +static void cs_deassert(struct spi_device *spi) { - struct chip_data *chip = - spi_get_ctldata(drv_data->master->cur_msg->spi); + struct chip_data *chip = spi_get_ctldata(spi); + struct driver_data *drv_data = + spi_controller_get_devdata(spi->controller); unsigned long timeout; if (drv_data->ssp_type == CE4100_SSP) @@ -437,7 +443,15 @@ static void cs_deassert(struct driver_data *drv_data) } if (is_lpss_ssp(drv_data)) - lpss_ssp_cs_control(drv_data, false); + lpss_ssp_cs_control(spi, false); +} + +static void pxa2xx_spi_set_cs(struct spi_device *spi, bool level) +{ + if (level) + cs_deassert(spi); + else + cs_assert(spi); } int pxa2xx_spi_flush(struct driver_data *drv_data) @@ -549,70 +563,6 @@ static int u32_reader(struct driver_data *drv_data) return drv_data->rx == drv_data->rx_end; } -void *pxa2xx_spi_next_transfer(struct driver_data *drv_data) -{ - struct spi_message *msg = drv_data->master->cur_msg; - struct spi_transfer *trans = drv_data->cur_transfer; - - /* Move to next transfer */ - if (trans->transfer_list.next != &msg->transfers) { - drv_data->cur_transfer = - list_entry(trans->transfer_list.next, - struct spi_transfer, - transfer_list); - return RUNNING_STATE; - } else - return DONE_STATE; -} - -/* caller already set message->status; dma and pio irqs are blocked */ -static void giveback(struct driver_data *drv_data) -{ - struct spi_transfer* last_transfer; - struct spi_message *msg; - - msg = drv_data->master->cur_msg; - drv_data->cur_transfer = NULL; - - last_transfer = list_last_entry(&msg->transfers, struct spi_transfer, - transfer_list); - - /* Delay if requested before any change in chip select */ - if (last_transfer->delay_usecs) - udelay(last_transfer->delay_usecs); - - /* Drop chip select UNLESS cs_change is true or we are returning - * a message with an error, or next message is for another chip - */ - if (!last_transfer->cs_change) - cs_deassert(drv_data); - else { - struct spi_message *next_msg; - - /* Holding of cs was hinted, but we need to make sure - * the next message is for the same chip. Don't waste - * time with the following tests unless this was hinted. - * - * We cannot postpone this until pump_messages, because - * after calling msg->complete (below) the driver that - * sent the current message could be unloaded, which - * could invalidate the cs_control() callback... - */ - - /* get a pointer to the next message, if any */ - next_msg = spi_get_next_queued_message(drv_data->master); - - /* see if the next and current messages point - * to the same chip - */ - if ((next_msg && next_msg->spi != msg->spi) || - msg->state == ERROR_STATE) - cs_deassert(drv_data); - } - - spi_finalize_current_message(drv_data->master); -} - static void reset_sccr1(struct driver_data *drv_data) { struct chip_data *chip = @@ -648,8 +598,8 @@ static void int_error_stop(struct driver_data *drv_data, const char* msg) dev_err(&drv_data->pdev->dev, "%s\n", msg); - drv_data->master->cur_msg->state = ERROR_STATE; - tasklet_schedule(&drv_data->pump_transfers); + drv_data->master->cur_msg->status = -EIO; + spi_finalize_current_transfer(drv_data->master); } static void int_transfer_complete(struct driver_data *drv_data) @@ -660,19 +610,7 @@ static void int_transfer_complete(struct driver_data *drv_data) if (!pxa25x_ssp_comp(drv_data)) pxa2xx_spi_write(drv_data, SSTO, 0); - /* Update total byte transferred return count actual bytes read */ - drv_data->master->cur_msg->actual_length += drv_data->len - - (drv_data->rx_end - drv_data->rx); - - /* Transfer delays and chip select release are - * handled in pump_transfers or giveback - */ - - /* Move to next transfer */ - drv_data->master->cur_msg->state = pxa2xx_spi_next_transfer(drv_data); - - /* Schedule transfer tasklet */ - tasklet_schedule(&drv_data->pump_transfers); + spi_finalize_current_transfer(drv_data->master); } static irqreturn_t interrupt_transfer(struct driver_data *drv_data) @@ -973,17 +911,16 @@ static bool pxa2xx_spi_can_dma(struct spi_controller *master, xfer->len >= chip->dma_burst_size; } -static void pump_transfers(unsigned long data) +static int pxa2xx_spi_transfer_one(struct spi_controller *master, + struct spi_device *spi, + struct spi_transfer *transfer) { - struct driver_data *drv_data = (struct driver_data *)data; - struct spi_controller *master = drv_data->master; + struct driver_data *drv_data = spi_controller_get_devdata(master); struct spi_message *message = master->cur_msg; struct chip_data *chip = spi_get_ctldata(message->spi); u32 dma_thresh = chip->dma_threshold; u32 dma_burst = chip->dma_burst_size; u32 change_mask = pxa2xx_spi_get_ssrc1_change_mask(drv_data); - struct spi_transfer *transfer; - struct spi_transfer *previous; u32 clk_div; u8 bits; u32 speed; @@ -992,36 +929,6 @@ static void pump_transfers(unsigned long data) int err; int dma_mapped; - /* Get current state information */ - transfer = drv_data->cur_transfer; - - /* Handle for abort */ - if (message->state == ERROR_STATE) { - message->status = -EIO; - giveback(drv_data); - return; - } - - /* Handle end of message */ - if (message->state == DONE_STATE) { - message->status = 0; - giveback(drv_data); - return; - } - - /* Delay if requested at end of transfer before CS change */ - if (message->state == RUNNING_STATE) { - previous = list_entry(transfer->transfer_list.prev, - struct spi_transfer, - transfer_list); - if (previous->delay_usecs) - udelay(previous->delay_usecs); - - /* Drop chip select only if cs_change is requested */ - if (previous->cs_change) - cs_deassert(drv_data); - } - /* Check if we can DMA this transfer */ if (transfer->len > MAX_DMA_LEN && chip->enable_dma) { @@ -1029,34 +936,27 @@ static void pump_transfers(unsigned long data) if (message->is_dma_mapped || transfer->rx_dma || transfer->tx_dma) { dev_err(&drv_data->pdev->dev, - "pump_transfers: mapped transfer length of " - "%u is greater than %d\n", + "Mapped transfer length of %u is greater than %d\n", transfer->len, MAX_DMA_LEN); - message->status = -EINVAL; - giveback(drv_data); - return; + return -EINVAL; } /* warn ... we force this to PIO mode */ dev_warn_ratelimited(&message->spi->dev, - "pump_transfers: DMA disabled for transfer length %ld " - "greater than %d\n", - (long)drv_data->len, MAX_DMA_LEN); + "DMA disabled for transfer length %ld greater than %d\n", + (long)transfer->len, MAX_DMA_LEN); } /* Setup the transfer state based on the type of transfer */ if (pxa2xx_spi_flush(drv_data) == 0) { - dev_err(&drv_data->pdev->dev, "pump_transfers: flush failed\n"); - message->status = -EIO; - giveback(drv_data); - return; + dev_err(&drv_data->pdev->dev, "Flush failed\n"); + return -EIO; } drv_data->n_bytes = chip->n_bytes; drv_data->tx = (void *)transfer->tx_buf; drv_data->tx_end = drv_data->tx + transfer->len; drv_data->rx = transfer->rx_buf; drv_data->rx_end = drv_data->rx + transfer->len; - drv_data->len = transfer->len; drv_data->write = drv_data->tx ? chip->write : null_writer; drv_data->read = drv_data->rx ? chip->read : null_reader; @@ -1095,11 +995,9 @@ static void pump_transfers(unsigned long data) bits, &dma_burst, &dma_thresh)) dev_warn_ratelimited(&message->spi->dev, - "pump_transfers: DMA burst size reduced to match bits_per_word\n"); + "DMA burst size reduced to match bits_per_word\n"); } - message->state = RUNNING_STATE; - dma_mapped = master->can_dma && master->can_dma(master, message->spi, transfer) && master->cur_msg_mapped; @@ -1108,12 +1006,9 @@ static void pump_transfers(unsigned long data) /* Ensure we have the correct interrupt handler */ drv_data->transfer_handler = pxa2xx_spi_dma_transfer; - err = pxa2xx_spi_dma_prepare(drv_data, dma_burst); - if (err) { - message->status = err; - giveback(drv_data); - return; - } + err = pxa2xx_spi_dma_prepare(drv_data, transfer); + if (err) + return err; /* Clear status and start DMA engine */ cr1 = chip->cr1 | dma_thresh | drv_data->dma_cr1; @@ -1175,27 +1070,40 @@ static void pump_transfers(unsigned long data) pxa2xx_spi_write(drv_data, SSTO, chip->timeout); } - cs_assert(drv_data); - - /* after chip select, release the data by enabling service - * requests and interrupts, without changing any mode bits */ + /* + * Release the data by enabling service requests and interrupts, + * without changing any mode bits + */ pxa2xx_spi_write(drv_data, SSCR1, cr1); + + return 1; } -static int pxa2xx_spi_transfer_one_message(struct spi_controller *master, - struct spi_message *msg) +static void pxa2xx_spi_handle_err(struct spi_controller *master, + struct spi_message *msg) { struct driver_data *drv_data = spi_controller_get_devdata(master); - /* Initial message state*/ - msg->state = START_STATE; - drv_data->cur_transfer = list_entry(msg->transfers.next, - struct spi_transfer, - transfer_list); + /* Disable the SSP */ + pxa2xx_spi_write(drv_data, SSCR0, + pxa2xx_spi_read(drv_data, SSCR0) & ~SSCR0_SSE); + /* Clear and disable interrupts and service requests */ + write_SSSR_CS(drv_data, drv_data->clear_sr); + pxa2xx_spi_write(drv_data, SSCR1, + pxa2xx_spi_read(drv_data, SSCR1) + & ~(drv_data->int_cr1 | drv_data->dma_cr1)); + if (!pxa25x_ssp_comp(drv_data)) + pxa2xx_spi_write(drv_data, SSTO, 0); - /* Mark as busy and launch transfers */ - tasklet_schedule(&drv_data->pump_transfers); - return 0; + /* + * Stop the DMA if running. Note DMA callback handler may have unset + * the dma_running already, which is fine as stopping is not needed + * then but we shouldn't rely this flag for anything else than + * stopping. For instance to differentiate between PIO and DMA + * transfers. + */ + if (atomic_read(&drv_data->dma_running)) + pxa2xx_spi_dma_stop(drv_data); } static int pxa2xx_spi_unprepare_transfer(struct spi_controller *master) @@ -1651,7 +1559,9 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) master->dma_alignment = DMA_ALIGNMENT; master->cleanup = cleanup; master->setup = setup; - master->transfer_one_message = pxa2xx_spi_transfer_one_message; + master->set_cs = pxa2xx_spi_set_cs; + master->transfer_one = pxa2xx_spi_transfer_one; + master->handle_err = pxa2xx_spi_handle_err; master->unprepare_transfer_hardware = pxa2xx_spi_unprepare_transfer; master->fw_translate_cs = pxa2xx_spi_fw_translate_cs; master->auto_runtime_pm = true; @@ -1702,7 +1612,9 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) } /* Enable SOC clock */ - clk_prepare_enable(ssp->clk); + status = clk_prepare_enable(ssp->clk); + if (status) + goto out_error_dma_irq_alloc; master->max_speed_hz = clk_get_rate(ssp->clk); @@ -1787,9 +1699,6 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) } } - tasklet_init(&drv_data->pump_transfers, pump_transfers, - (unsigned long)drv_data); - pm_runtime_set_autosuspend_delay(&pdev->dev, 50); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_active(&pdev->dev); @@ -1809,6 +1718,8 @@ out_error_clock_enabled: pm_runtime_put_noidle(&pdev->dev); pm_runtime_disable(&pdev->dev); clk_disable_unprepare(ssp->clk); + +out_error_dma_irq_alloc: pxa2xx_spi_dma_release(drv_data); free_irq(ssp->irq, drv_data); @@ -1882,8 +1793,11 @@ static int pxa2xx_spi_resume(struct device *dev) int status; /* Enable the SSP clock */ - if (!pm_runtime_suspended(dev)) - clk_prepare_enable(ssp->clk); + if (!pm_runtime_suspended(dev)) { + status = clk_prepare_enable(ssp->clk); + if (status) + return status; + } /* Restore LPSS private register bits */ if (is_lpss_ssp(drv_data)) @@ -1912,9 +1826,10 @@ static int pxa2xx_spi_runtime_suspend(struct device *dev) static int pxa2xx_spi_runtime_resume(struct device *dev) { struct driver_data *drv_data = dev_get_drvdata(dev); + int status; - clk_prepare_enable(drv_data->ssp->clk); - return 0; + status = clk_prepare_enable(drv_data->ssp->clk); + return status; } #endif diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h index 0ae7defd3492..513c53aaeab2 100644 --- a/drivers/spi/spi-pxa2xx.h +++ b/drivers/spi/spi-pxa2xx.h @@ -46,15 +46,10 @@ struct driver_data { u32 clear_sr; u32 mask_sr; - /* Message Transfer pump */ - struct tasklet_struct pump_transfers; - /* DMA engine support */ atomic_t dma_running; - /* Current message transfer state info */ - struct spi_transfer *cur_transfer; - size_t len; + /* Current transfer state info */ void *tx; void *tx_end; void *rx; @@ -104,11 +99,6 @@ static inline void pxa2xx_spi_write(const struct driver_data *drv_data, __raw_writel(val, drv_data->ioaddr + reg); } -#define START_STATE ((void *)0) -#define RUNNING_STATE ((void *)1) -#define DONE_STATE ((void *)2) -#define ERROR_STATE ((void *)-1) - #define DMA_ALIGNMENT 8 static inline int pxa25x_ssp_comp(struct driver_data *drv_data) @@ -133,14 +123,15 @@ static inline void write_SSSR_CS(struct driver_data *drv_data, u32 val) } extern int pxa2xx_spi_flush(struct driver_data *drv_data); -extern void *pxa2xx_spi_next_transfer(struct driver_data *drv_data); #define MAX_DMA_LEN SZ_64K #define DEFAULT_DMA_CR1 (SSCR1_TSRE | SSCR1_RSRE | SSCR1_TRAIL) extern irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data); -extern int pxa2xx_spi_dma_prepare(struct driver_data *drv_data, u32 dma_burst); +extern int pxa2xx_spi_dma_prepare(struct driver_data *drv_data, + struct spi_transfer *xfer); extern void pxa2xx_spi_dma_start(struct driver_data *drv_data); +extern void pxa2xx_spi_dma_stop(struct driver_data *drv_data); extern int pxa2xx_spi_dma_setup(struct driver_data *drv_data); extern void pxa2xx_spi_dma_release(struct driver_data *drv_data); extern int pxa2xx_spi_set_dma_burst_and_threshold(struct chip_data *chip, diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index baa3a9fa2638..7b7151ec14c8 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -28,15 +28,15 @@ #define S3C64XX_SPI_CH_CFG 0x00 #define S3C64XX_SPI_CLK_CFG 0x04 -#define S3C64XX_SPI_MODE_CFG 0x08 -#define S3C64XX_SPI_SLAVE_SEL 0x0C +#define S3C64XX_SPI_MODE_CFG 0x08 +#define S3C64XX_SPI_SLAVE_SEL 0x0C #define S3C64XX_SPI_INT_EN 0x10 #define S3C64XX_SPI_STATUS 0x14 #define S3C64XX_SPI_TX_DATA 0x18 #define S3C64XX_SPI_RX_DATA 0x1C -#define S3C64XX_SPI_PACKET_CNT 0x20 -#define S3C64XX_SPI_PENDING_CLR 0x24 -#define S3C64XX_SPI_SWAP_CFG 0x28 +#define S3C64XX_SPI_PACKET_CNT 0x20 +#define S3C64XX_SPI_PENDING_CLR 0x24 +#define S3C64XX_SPI_SWAP_CFG 0x28 #define S3C64XX_SPI_FB_CLK 0x2C #define S3C64XX_SPI_CH_HS_EN (1<<6) /* High Speed Enable */ @@ -77,9 +77,9 @@ #define S3C64XX_SPI_INT_TX_FIFORDY_EN (1<<0) #define S3C64XX_SPI_ST_RX_OVERRUN_ERR (1<<5) -#define S3C64XX_SPI_ST_RX_UNDERRUN_ERR (1<<4) +#define S3C64XX_SPI_ST_RX_UNDERRUN_ERR (1<<4) #define S3C64XX_SPI_ST_TX_OVERRUN_ERR (1<<3) -#define S3C64XX_SPI_ST_TX_UNDERRUN_ERR (1<<2) +#define S3C64XX_SPI_ST_TX_UNDERRUN_ERR (1<<2) #define S3C64XX_SPI_ST_RX_FIFORDY (1<<1) #define S3C64XX_SPI_ST_TX_FIFORDY (1<<0) @@ -100,7 +100,7 @@ #define S3C64XX_SPI_SWAP_TX_BIT (1<<1) #define S3C64XX_SPI_SWAP_TX_EN (1<<0) -#define S3C64XX_SPI_FBCLK_MSK (3<<0) +#define S3C64XX_SPI_FBCLK_MSK (3<<0) #define FIFO_LVL_MASK(i) ((i)->port_conf->fifo_lvl_mask[i->port_id]) #define S3C64XX_SPI_ST_TX_DONE(v, i) (((v) & \ @@ -156,7 +156,6 @@ struct s3c64xx_spi_port_config { * @ioclk: Pointer to the i/o clock between master and slave * @master: Pointer to the SPI Protocol master. * @cntrlr_info: Platform specific data for the controller this driver manages. - * @tgl_spi: Pointer to the last CS left untoggled by the cs_change hint. * @lock: Controller specific lock. * @state: Set of FLAGS to indicate status. * @rx_dmach: Controller's DMA channel for Rx. @@ -177,7 +176,6 @@ struct s3c64xx_spi_driver_data { struct platform_device *pdev; struct spi_master *master; struct s3c64xx_spi_info *cntrlr_info; - struct spi_device *tgl_spi; spinlock_t lock; unsigned long sfr_start; struct completion xfer_completion; @@ -190,7 +188,7 @@ struct s3c64xx_spi_driver_data { unsigned int port_id; }; -static void flush_fifo(struct s3c64xx_spi_driver_data *sdd) +static void s3c64xx_flush_fifo(struct s3c64xx_spi_driver_data *sdd) { void __iomem *regs = sdd->regs; unsigned long loops; @@ -350,9 +348,8 @@ static bool s3c64xx_spi_can_dma(struct spi_master *master, return xfer->len > (FIFO_LVL_MASK(sdd) >> 1) + 1; } -static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, - struct spi_device *spi, - struct spi_transfer *xfer, int dma_mode) +static void s3c64xx_enable_datapath(struct s3c64xx_spi_driver_data *sdd, + struct spi_transfer *xfer, int dma_mode) { void __iomem *regs = sdd->regs; u32 modecfg, chcfg; @@ -442,8 +439,8 @@ static u32 s3c64xx_spi_wait_for_timeout(struct s3c64xx_spi_driver_data *sdd, return RX_FIFO_LVL(status, sdd); } -static int wait_for_dma(struct s3c64xx_spi_driver_data *sdd, - struct spi_transfer *xfer) +static int s3c64xx_wait_for_dma(struct s3c64xx_spi_driver_data *sdd, + struct spi_transfer *xfer) { void __iomem *regs = sdd->regs; unsigned long val; @@ -485,8 +482,8 @@ static int wait_for_dma(struct s3c64xx_spi_driver_data *sdd, return 0; } -static int wait_for_pio(struct s3c64xx_spi_driver_data *sdd, - struct spi_transfer *xfer) +static int s3c64xx_wait_for_pio(struct s3c64xx_spi_driver_data *sdd, + struct spi_transfer *xfer) { void __iomem *regs = sdd->regs; unsigned long val; @@ -505,6 +502,8 @@ static int wait_for_pio(struct s3c64xx_spi_driver_data *sdd, status = readl(regs + S3C64XX_SPI_STATUS); } while (RX_FIFO_LVL(status, sdd) < xfer->len && --val); + if (!val) + return -EIO; /* If it was only Tx */ if (!xfer->rx_buf) { @@ -635,11 +634,15 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master, struct spi_transfer *xfer) { struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); + const unsigned int fifo_len = (FIFO_LVL_MASK(sdd) >> 1) + 1; + const void *tx_buf = NULL; + void *rx_buf = NULL; + int target_len = 0, origin_len = 0; + int use_dma = 0; int status; u32 speed; u8 bpw; unsigned long flags; - int use_dma; reinit_completion(&sdd->xfer_completion); @@ -654,48 +657,77 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master, s3c64xx_spi_config(sdd); } - /* Polling method for xfers not bigger than FIFO capacity */ - use_dma = 0; - if (!is_polling(sdd) && - (sdd->rx_dma.ch && sdd->tx_dma.ch && - (xfer->len > ((FIFO_LVL_MASK(sdd) >> 1) + 1)))) + if (!is_polling(sdd) && (xfer->len > fifo_len) && + sdd->rx_dma.ch && sdd->tx_dma.ch) { use_dma = 1; - spin_lock_irqsave(&sdd->lock, flags); + } else if (is_polling(sdd) && xfer->len > fifo_len) { + tx_buf = xfer->tx_buf; + rx_buf = xfer->rx_buf; + origin_len = xfer->len; - /* Pending only which is to be done */ - sdd->state &= ~RXBUSY; - sdd->state &= ~TXBUSY; + target_len = xfer->len; + if (xfer->len > fifo_len) + xfer->len = fifo_len; + } - enable_datapath(sdd, spi, xfer, use_dma); + do { + spin_lock_irqsave(&sdd->lock, flags); - /* Start the signals */ - s3c64xx_spi_set_cs(spi, true); + /* Pending only which is to be done */ + sdd->state &= ~RXBUSY; + sdd->state &= ~TXBUSY; - spin_unlock_irqrestore(&sdd->lock, flags); + s3c64xx_enable_datapath(sdd, xfer, use_dma); - if (use_dma) - status = wait_for_dma(sdd, xfer); - else - status = wait_for_pio(sdd, xfer); - - if (status) { - dev_err(&spi->dev, "I/O Error: rx-%d tx-%d res:rx-%c tx-%c len-%d\n", - xfer->rx_buf ? 1 : 0, xfer->tx_buf ? 1 : 0, - (sdd->state & RXBUSY) ? 'f' : 'p', - (sdd->state & TXBUSY) ? 'f' : 'p', - xfer->len); - - if (use_dma) { - if (xfer->tx_buf != NULL - && (sdd->state & TXBUSY)) - dmaengine_terminate_all(sdd->tx_dma.ch); - if (xfer->rx_buf != NULL - && (sdd->state & RXBUSY)) - dmaengine_terminate_all(sdd->rx_dma.ch); + /* Start the signals */ + s3c64xx_spi_set_cs(spi, true); + + spin_unlock_irqrestore(&sdd->lock, flags); + + if (use_dma) + status = s3c64xx_wait_for_dma(sdd, xfer); + else + status = s3c64xx_wait_for_pio(sdd, xfer); + + if (status) { + dev_err(&spi->dev, + "I/O Error: rx-%d tx-%d res:rx-%c tx-%c len-%d\n", + xfer->rx_buf ? 1 : 0, xfer->tx_buf ? 1 : 0, + (sdd->state & RXBUSY) ? 'f' : 'p', + (sdd->state & TXBUSY) ? 'f' : 'p', + xfer->len); + + if (use_dma) { + if (xfer->tx_buf && (sdd->state & TXBUSY)) + dmaengine_terminate_all(sdd->tx_dma.ch); + if (xfer->rx_buf && (sdd->state & RXBUSY)) + dmaengine_terminate_all(sdd->rx_dma.ch); + } + } else { + s3c64xx_flush_fifo(sdd); } - } else { - flush_fifo(sdd); + if (target_len > 0) { + target_len -= xfer->len; + + if (xfer->tx_buf) + xfer->tx_buf += xfer->len; + + if (xfer->rx_buf) + xfer->rx_buf += xfer->len; + + if (target_len > fifo_len) + xfer->len = fifo_len; + else + xfer->len = target_len; + } + } while (target_len > 0); + + if (origin_len) { + /* Restore original xfer buffers and length */ + xfer->tx_buf = tx_buf; + xfer->rx_buf = rx_buf; + xfer->len = origin_len; } return status; @@ -891,7 +923,7 @@ static irqreturn_t s3c64xx_spi_irq(int irq, void *data) return IRQ_HANDLED; } -static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel) +static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd) { struct s3c64xx_spi_info *sci = sdd->cntrlr_info; void __iomem *regs = sdd->regs; @@ -929,7 +961,7 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel) val |= (S3C64XX_SPI_TRAILCNT << S3C64XX_SPI_TRAILCNT_OFF); writel(val, regs + S3C64XX_SPI_MODE_CFG); - flush_fifo(sdd); + s3c64xx_flush_fifo(sdd); } #ifdef CONFIG_OF @@ -1145,7 +1177,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) pm_runtime_get_sync(&pdev->dev); /* Setup Deufult Mode */ - s3c64xx_spi_hwinit(sdd, sdd->port_id); + s3c64xx_spi_hwinit(sdd); spin_lock_init(&sdd->lock); init_completion(&sdd->xfer_completion); @@ -1260,8 +1292,6 @@ static int s3c64xx_spi_resume(struct device *dev) if (ret < 0) return ret; - s3c64xx_spi_hwinit(sdd, sdd->port_id); - return spi_master_resume(master); } #endif /* CONFIG_PM_SLEEP */ @@ -1299,6 +1329,8 @@ static int s3c64xx_spi_runtime_resume(struct device *dev) if (ret != 0) goto err_disable_src_clk; + s3c64xx_spi_hwinit(sdd); + return 0; err_disable_src_clk: @@ -1344,15 +1376,6 @@ static struct s3c64xx_spi_port_config exynos4_spi_port_config = { .clk_from_cmu = true, }; -static struct s3c64xx_spi_port_config exynos5440_spi_port_config = { - .fifo_lvl_mask = { 0x1ff }, - .rx_lvl_offset = 15, - .tx_st_done = 25, - .high_speed = true, - .clk_from_cmu = true, - .quirks = S3C64XX_SPI_QUIRK_POLL, -}; - static struct s3c64xx_spi_port_config exynos7_spi_port_config = { .fifo_lvl_mask = { 0x1ff, 0x7F, 0x7F, 0x7F, 0x7F, 0x1ff}, .rx_lvl_offset = 15, @@ -1396,9 +1419,6 @@ static const struct of_device_id s3c64xx_spi_dt_match[] = { { .compatible = "samsung,exynos4210-spi", .data = (void *)&exynos4_spi_port_config, }, - { .compatible = "samsung,exynos5440-spi", - .data = (void *)&exynos5440_spi_port_config, - }, { .compatible = "samsung,exynos7-spi", .data = (void *)&exynos7_spi_port_config, }, diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 8171eedbfc90..0e74cbf9929d 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -39,7 +39,7 @@ struct sh_msiof_chipdata { u16 tx_fifo_size; u16 rx_fifo_size; u16 master_flags; - u16 min_div; + u16 min_div_pow; }; struct sh_msiof_spi_priv { @@ -51,7 +51,7 @@ struct sh_msiof_spi_priv { struct completion done; unsigned int tx_fifo_size; unsigned int rx_fifo_size; - unsigned int min_div; + unsigned int min_div_pow; void *tx_dma_page; void *rx_dma_page; dma_addr_t tx_dma_addr; @@ -249,43 +249,46 @@ static irqreturn_t sh_msiof_spi_irq(int irq, void *data) return IRQ_HANDLED; } -static struct { - unsigned short div; - unsigned short brdv; -} const sh_msiof_spi_div_table[] = { - { 1, SCR_BRDV_DIV_1 }, - { 2, SCR_BRDV_DIV_2 }, - { 4, SCR_BRDV_DIV_4 }, - { 8, SCR_BRDV_DIV_8 }, - { 16, SCR_BRDV_DIV_16 }, - { 32, SCR_BRDV_DIV_32 }, +static const u32 sh_msiof_spi_div_array[] = { + SCR_BRDV_DIV_1, SCR_BRDV_DIV_2, SCR_BRDV_DIV_4, + SCR_BRDV_DIV_8, SCR_BRDV_DIV_16, SCR_BRDV_DIV_32, }; static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p, unsigned long parent_rate, u32 spi_hz) { - unsigned long div = 1024; + unsigned long div; u32 brps, scr; - size_t k; + unsigned int div_pow = p->min_div_pow; - if (!WARN_ON(!spi_hz || !parent_rate)) - div = DIV_ROUND_UP(parent_rate, spi_hz); - - div = max_t(unsigned long, div, p->min_div); + if (!spi_hz || !parent_rate) { + WARN(1, "Invalid clock rate parameters %lu and %u\n", + parent_rate, spi_hz); + return; + } - for (k = 0; k < ARRAY_SIZE(sh_msiof_spi_div_table); k++) { - brps = DIV_ROUND_UP(div, sh_msiof_spi_div_table[k].div); + div = DIV_ROUND_UP(parent_rate, spi_hz); + if (div <= 1024) { /* SCR_BRDV_DIV_1 is valid only if BRPS is x 1/1 or x 1/2 */ - if (sh_msiof_spi_div_table[k].div == 1 && brps > 2) - continue; - if (brps <= 32) /* max of brdv is 32 */ - break; - } + if (!div_pow && div <= 32 && div > 2) + div_pow = 1; + + if (div_pow) + brps = (div + 1) >> div_pow; + else + brps = div; - k = min_t(int, k, ARRAY_SIZE(sh_msiof_spi_div_table) - 1); - brps = min_t(int, brps, 32); + for (; brps > 32; div_pow++) + brps = (brps + 1) >> 1; + } else { + /* Set transfer rate composite divisor to 2^5 * 32 = 1024 */ + dev_err(&p->pdev->dev, + "Requested SPI transfer rate %d is too low\n", spi_hz); + div_pow = 5; + brps = 32; + } - scr = sh_msiof_spi_div_table[k].brdv | SCR_BRPS(brps); + scr = sh_msiof_spi_div_array[div_pow] | SCR_BRPS(brps); sh_msiof_write(p, TSCR, scr); if (!(p->master->flags & SPI_MASTER_MUST_TX)) sh_msiof_write(p, RSCR, scr); @@ -564,14 +567,16 @@ static int sh_msiof_spi_setup(struct spi_device *spi) /* Configure native chip select mode/polarity early */ clr = MDR1_SYNCMD_MASK; - set = MDR1_TRMD | TMDR1_PCON | MDR1_SYNCMD_SPI; + set = MDR1_SYNCMD_SPI; if (spi->mode & SPI_CS_HIGH) clr |= BIT(MDR1_SYNCAC_SHIFT); else set |= BIT(MDR1_SYNCAC_SHIFT); pm_runtime_get_sync(&p->pdev->dev); tmp = sh_msiof_read(p, TMDR1) & ~clr; - sh_msiof_write(p, TMDR1, tmp | set); + sh_msiof_write(p, TMDR1, tmp | set | MDR1_TRMD | TMDR1_PCON); + tmp = sh_msiof_read(p, RMDR1) & ~clr; + sh_msiof_write(p, RMDR1, tmp | set); pm_runtime_put(&p->pdev->dev); p->native_cs_high = spi->mode & SPI_CS_HIGH; p->native_cs_inited = true; @@ -1041,21 +1046,21 @@ static const struct sh_msiof_chipdata sh_data = { .tx_fifo_size = 64, .rx_fifo_size = 64, .master_flags = 0, - .min_div = 1, + .min_div_pow = 0, }; static const struct sh_msiof_chipdata rcar_gen2_data = { .tx_fifo_size = 64, .rx_fifo_size = 64, .master_flags = SPI_MASTER_MUST_TX, - .min_div = 1, + .min_div_pow = 0, }; static const struct sh_msiof_chipdata rcar_gen3_data = { .tx_fifo_size = 64, .rx_fifo_size = 64, .master_flags = SPI_MASTER_MUST_TX, - .min_div = 2, + .min_div_pow = 1, }; static const struct of_device_id sh_msiof_match[] = { @@ -1319,7 +1324,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, p); p->master = master; p->info = info; - p->min_div = chipdata->min_div; + p->min_div_pow = chipdata->min_div_pow; init_completion(&p->done); diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c index ba9743fa2326..ad1e55d3d5d5 100644 --- a/drivers/spi/spi-stm32.c +++ b/drivers/spi/spi-stm32.c @@ -1129,7 +1129,7 @@ static int stm32_spi_probe(struct platform_device *pdev) if (!spi->clk_rate) { dev_err(&pdev->dev, "clk rate = 0\n"); ret = -EINVAL; - goto err_master_put; + goto err_clk_disable; } spi->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL); diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index c24d9b45a27c..5f19016bbf10 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -36,6 +36,7 @@ #include <linux/sizes.h> #include <linux/spi/spi.h> +#include <linux/spi/spi-mem.h> struct ti_qspi_regs { u32 clkctrl; @@ -50,6 +51,7 @@ struct ti_qspi { struct spi_master *master; void __iomem *base; void __iomem *mmap_base; + size_t mmap_size; struct regmap *ctrl_base; unsigned int ctrl_reg; struct clk *fclk; @@ -434,12 +436,10 @@ static int ti_qspi_dma_xfer(struct ti_qspi *qspi, dma_addr_t dma_dst, return 0; } -static int ti_qspi_dma_bounce_buffer(struct ti_qspi *qspi, - struct spi_flash_read_message *msg) +static int ti_qspi_dma_bounce_buffer(struct ti_qspi *qspi, loff_t offs, + void *to, size_t readsize) { - size_t readsize = msg->len; - void *to = msg->buf; - dma_addr_t dma_src = qspi->mmap_phys_base + msg->from; + dma_addr_t dma_src = qspi->mmap_phys_base + offs; int ret = 0; /* @@ -507,13 +507,14 @@ static void ti_qspi_disable_memory_map(struct spi_device *spi) qspi->mmap_enabled = false; } -static void ti_qspi_setup_mmap_read(struct spi_device *spi, - struct spi_flash_read_message *msg) +static void ti_qspi_setup_mmap_read(struct spi_device *spi, u8 opcode, + u8 data_nbits, u8 addr_width, + u8 dummy_bytes) { struct ti_qspi *qspi = spi_master_get_devdata(spi->master); - u32 memval = msg->read_opcode; + u32 memval = opcode; - switch (msg->data_nbits) { + switch (data_nbits) { case SPI_NBITS_QUAD: memval |= QSPI_SETUP_RD_QUAD; break; @@ -524,48 +525,64 @@ static void ti_qspi_setup_mmap_read(struct spi_device *spi, memval |= QSPI_SETUP_RD_NORMAL; break; } - memval |= ((msg->addr_width - 1) << QSPI_SETUP_ADDR_SHIFT | - msg->dummy_bytes << QSPI_SETUP_DUMMY_SHIFT); + memval |= ((addr_width - 1) << QSPI_SETUP_ADDR_SHIFT | + dummy_bytes << QSPI_SETUP_DUMMY_SHIFT); ti_qspi_write(qspi, memval, QSPI_SPI_SETUP_REG(spi->chip_select)); } -static bool ti_qspi_spi_flash_can_dma(struct spi_device *spi, - struct spi_flash_read_message *msg) +static int ti_qspi_exec_mem_op(struct spi_mem *mem, + const struct spi_mem_op *op) { - return virt_addr_valid(msg->buf); -} - -static int ti_qspi_spi_flash_read(struct spi_device *spi, - struct spi_flash_read_message *msg) -{ - struct ti_qspi *qspi = spi_master_get_devdata(spi->master); + struct ti_qspi *qspi = spi_master_get_devdata(mem->spi->master); + u32 from = 0; int ret = 0; + /* Only optimize read path. */ + if (!op->data.nbytes || op->data.dir != SPI_MEM_DATA_IN || + !op->addr.nbytes || op->addr.nbytes > 4) + return -ENOTSUPP; + + /* Address exceeds MMIO window size, fall back to regular mode. */ + from = op->addr.val; + if (from + op->data.nbytes > qspi->mmap_size) + return -ENOTSUPP; + mutex_lock(&qspi->list_lock); if (!qspi->mmap_enabled) - ti_qspi_enable_memory_map(spi); - ti_qspi_setup_mmap_read(spi, msg); + ti_qspi_enable_memory_map(mem->spi); + ti_qspi_setup_mmap_read(mem->spi, op->cmd.opcode, op->data.buswidth, + op->addr.nbytes, op->dummy.nbytes); if (qspi->rx_chan) { - if (msg->cur_msg_mapped) - ret = ti_qspi_dma_xfer_sg(qspi, msg->rx_sg, msg->from); - else - ret = ti_qspi_dma_bounce_buffer(qspi, msg); - if (ret) - goto err_unlock; + struct sg_table sgt; + + if (virt_addr_valid(op->data.buf.in) && + !spi_controller_dma_map_mem_op_data(mem->spi->master, op, + &sgt)) { + ret = ti_qspi_dma_xfer_sg(qspi, sgt, from); + spi_controller_dma_unmap_mem_op_data(mem->spi->master, + op, &sgt); + } else { + ret = ti_qspi_dma_bounce_buffer(qspi, from, + op->data.buf.in, + op->data.nbytes); + } } else { - memcpy_fromio(msg->buf, qspi->mmap_base + msg->from, msg->len); + memcpy_fromio(op->data.buf.in, qspi->mmap_base + from, + op->data.nbytes); } - msg->retlen = msg->len; -err_unlock: mutex_unlock(&qspi->list_lock); return ret; } +static const struct spi_controller_mem_ops ti_qspi_mem_ops = { + .exec_op = ti_qspi_exec_mem_op, +}; + static int ti_qspi_start_transfer_one(struct spi_master *master, struct spi_message *m) { @@ -672,7 +689,7 @@ static int ti_qspi_probe(struct platform_device *pdev) master->dev.of_node = pdev->dev.of_node; master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) | SPI_BPW_MASK(8); - master->spi_flash_read = ti_qspi_spi_flash_read; + master->mem_ops = &ti_qspi_mem_ops; if (!of_property_read_u32(np, "num-cs", &num_cs)) master->num_chipselect = num_cs; @@ -702,6 +719,9 @@ static int ti_qspi_probe(struct platform_device *pdev) } } + if (res_mmap) + qspi->mmap_size = resource_size(res_mmap); + irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "no irq resource?\n"); @@ -770,7 +790,6 @@ static int ti_qspi_probe(struct platform_device *pdev) dma_release_channel(qspi->rx_chan); goto no_dma; } - master->spi_flash_can_dma = ti_qspi_spi_flash_can_dma; master->dma_rx = qspi->rx_chan; init_completion(&qspi->transfer_complete); if (res_mmap) @@ -784,7 +803,7 @@ no_dma: "mmap failed with error %ld using PIO mode\n", PTR_ERR(qspi->mmap_base)); qspi->mmap_base = NULL; - master->spi_flash_read = NULL; + master->mem_ops = NULL; } } qspi->mmap_enabled = false; diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c index 18aeaceee286..cc4d31033494 100644 --- a/drivers/spi/spi-zynqmp-gqspi.c +++ b/drivers/spi/spi-zynqmp-gqspi.c @@ -20,6 +20,7 @@ #include <linux/of_irq.h> #include <linux/of_address.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/spi/spi.h> #include <linux/spinlock.h> #include <linux/workqueue.h> @@ -135,6 +136,7 @@ #define GQSPI_DMA_UNALIGN 0x3 #define GQSPI_DEFAULT_NUM_CS 1 /* Default number of chip selects */ +#define SPI_AUTOSUSPEND_TIMEOUT 3000 enum mode_type {GQSPI_MODE_IO, GQSPI_MODE_DMA}; /** @@ -356,21 +358,9 @@ static void zynqmp_qspi_copy_read_data(struct zynqmp_qspi *xqspi, static int zynqmp_prepare_transfer_hardware(struct spi_master *master) { struct zynqmp_qspi *xqspi = spi_master_get_devdata(master); - int ret; - - ret = clk_enable(xqspi->refclk); - if (ret) - return ret; - - ret = clk_enable(xqspi->pclk); - if (ret) - goto clk_err; zynqmp_gqspi_write(xqspi, GQSPI_EN_OFST, GQSPI_EN_MASK); return 0; -clk_err: - clk_disable(xqspi->refclk); - return ret; } /** @@ -387,8 +377,6 @@ static int zynqmp_unprepare_transfer_hardware(struct spi_master *master) struct zynqmp_qspi *xqspi = spi_master_get_devdata(master); zynqmp_gqspi_write(xqspi, GQSPI_EN_OFST, 0x0); - clk_disable(xqspi->refclk); - clk_disable(xqspi->pclk); return 0; } @@ -918,8 +906,7 @@ static int zynqmp_qspi_start_transfer(struct spi_master *master, */ static int __maybe_unused zynqmp_qspi_suspend(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct spi_master *master = platform_get_drvdata(pdev); + struct spi_master *master = dev_get_drvdata(dev); spi_master_suspend(master); @@ -939,8 +926,7 @@ static int __maybe_unused zynqmp_qspi_suspend(struct device *dev) */ static int __maybe_unused zynqmp_qspi_resume(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct spi_master *master = platform_get_drvdata(pdev); + struct spi_master *master = dev_get_drvdata(dev); struct zynqmp_qspi *xqspi = spi_master_get_devdata(master); int ret = 0; @@ -959,11 +945,67 @@ static int __maybe_unused zynqmp_qspi_resume(struct device *dev) spi_master_resume(master); + clk_disable(xqspi->refclk); + clk_disable(xqspi->pclk); return 0; } -static SIMPLE_DEV_PM_OPS(zynqmp_qspi_dev_pm_ops, zynqmp_qspi_suspend, - zynqmp_qspi_resume); +/** + * zynqmp_runtime_suspend - Runtime suspend method for the SPI driver + * @dev: Address of the platform_device structure + * + * This function disables the clocks + * + * Return: Always 0 + */ +static int __maybe_unused zynqmp_runtime_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct spi_master *master = platform_get_drvdata(pdev); + struct zynqmp_qspi *xqspi = spi_master_get_devdata(master); + + clk_disable(xqspi->refclk); + clk_disable(xqspi->pclk); + + return 0; +} + +/** + * zynqmp_runtime_resume - Runtime resume method for the SPI driver + * @dev: Address of the platform_device structure + * + * This function enables the clocks + * + * Return: 0 on success and error value on error + */ +static int __maybe_unused zynqmp_runtime_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct spi_master *master = platform_get_drvdata(pdev); + struct zynqmp_qspi *xqspi = spi_master_get_devdata(master); + int ret; + + ret = clk_enable(xqspi->pclk); + if (ret) { + dev_err(dev, "Cannot enable APB clock.\n"); + return ret; + } + + ret = clk_enable(xqspi->refclk); + if (ret) { + dev_err(dev, "Cannot enable device clock.\n"); + clk_disable(xqspi->pclk); + return ret; + } + + return 0; +} + +static const struct dev_pm_ops zynqmp_qspi_dev_pm_ops = { + SET_RUNTIME_PM_OPS(zynqmp_runtime_suspend, + zynqmp_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(zynqmp_qspi_suspend, zynqmp_qspi_resume) +}; /** * zynqmp_qspi_probe: Probe method for the QSPI driver @@ -1023,9 +1065,15 @@ static int zynqmp_qspi_probe(struct platform_device *pdev) goto clk_dis_pclk; } + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); /* QSPI controller initializations */ zynqmp_qspi_init_hw(xqspi); + pm_runtime_mark_last_busy(&pdev->dev); + pm_runtime_put_autosuspend(&pdev->dev); xqspi->irq = platform_get_irq(pdev, 0); if (xqspi->irq <= 0) { ret = -ENXIO; @@ -1063,6 +1111,8 @@ static int zynqmp_qspi_probe(struct platform_device *pdev) return 0; clk_dis_all: + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_disable(&pdev->dev); clk_disable_unprepare(xqspi->refclk); clk_dis_pclk: clk_disable_unprepare(xqspi->pclk); @@ -1090,6 +1140,8 @@ static int zynqmp_qspi_remove(struct platform_device *pdev) zynqmp_gqspi_write(xqspi, GQSPI_EN_OFST, 0x0); clk_disable_unprepare(xqspi->refclk); clk_disable_unprepare(xqspi->pclk); + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_disable(&pdev->dev); spi_unregister_master(master); diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 7b213faa0a2b..efc624f9e490 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -28,6 +28,7 @@ #include <linux/slab.h> #include <linux/mod_devicetable.h> #include <linux/spi/spi.h> +#include <linux/spi/spi-mem.h> #include <linux/of_gpio.h> #include <linux/pm_runtime.h> #include <linux/pm_domain.h> @@ -46,6 +47,8 @@ #define CREATE_TRACE_POINTS #include <trace/events/spi.h> +#include "internals.h" + static DEFINE_IDR(spi_master_idr); static void spidev_release(struct device *dev) @@ -356,11 +359,12 @@ static int spi_drv_probe(struct device *dev) } ret = dev_pm_domain_attach(dev, true); - if (ret != -EPROBE_DEFER) { - ret = sdrv->probe(spi); - if (ret) - dev_pm_domain_detach(dev, true); - } + if (ret) + return ret; + + ret = sdrv->probe(spi); + if (ret) + dev_pm_domain_detach(dev, true); return ret; } @@ -740,9 +744,9 @@ static void spi_set_cs(struct spi_device *spi, bool enable) } #ifdef CONFIG_HAS_DMA -static int spi_map_buf(struct spi_controller *ctlr, struct device *dev, - struct sg_table *sgt, void *buf, size_t len, - enum dma_data_direction dir) +int spi_map_buf(struct spi_controller *ctlr, struct device *dev, + struct sg_table *sgt, void *buf, size_t len, + enum dma_data_direction dir) { const bool vmalloced_buf = is_vmalloc_addr(buf); unsigned int max_seg_size = dma_get_max_seg_size(dev); @@ -821,8 +825,8 @@ static int spi_map_buf(struct spi_controller *ctlr, struct device *dev, return 0; } -static void spi_unmap_buf(struct spi_controller *ctlr, struct device *dev, - struct sg_table *sgt, enum dma_data_direction dir) +void spi_unmap_buf(struct spi_controller *ctlr, struct device *dev, + struct sg_table *sgt, enum dma_data_direction dir) { if (sgt->orig_nents) { dma_unmap_sg(dev, sgt->sgl, sgt->orig_nents, dir); @@ -907,19 +911,6 @@ static int __spi_unmap_msg(struct spi_controller *ctlr, struct spi_message *msg) return 0; } #else /* !CONFIG_HAS_DMA */ -static inline int spi_map_buf(struct spi_controller *ctlr, struct device *dev, - struct sg_table *sgt, void *buf, size_t len, - enum dma_data_direction dir) -{ - return -EINVAL; -} - -static inline void spi_unmap_buf(struct spi_controller *ctlr, - struct device *dev, struct sg_table *sgt, - enum dma_data_direction dir) -{ -} - static inline int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg) { @@ -1222,6 +1213,7 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread) if (!was_busy && ctlr->auto_runtime_pm) { ret = pm_runtime_get_sync(ctlr->dev.parent); if (ret < 0) { + pm_runtime_put_noidle(ctlr->dev.parent); dev_err(&ctlr->dev, "Failed to power device: %d\n", ret); mutex_unlock(&ctlr->io_mutex); @@ -1533,6 +1525,22 @@ err_init_queue: return ret; } +/** + * spi_flush_queue - Send all pending messages in the queue from the callers' + * context + * @ctlr: controller to process queue for + * + * This should be used when one wants to ensure all pending messages have been + * sent before doing something. Is used by the spi-mem code to make sure SPI + * memory operations do not preempt regular SPI transfers that have been queued + * before the spi-mem operation. + */ +void spi_flush_queue(struct spi_controller *ctlr) +{ + if (ctlr->transfer == spi_queued_transfer) + __spi_pump_messages(ctlr, false); +} + /*-------------------------------------------------------------------------*/ #if defined(CONFIG_OF) @@ -2063,6 +2071,26 @@ static int of_spi_register_master(struct spi_controller *ctlr) } #endif +static int spi_controller_check_ops(struct spi_controller *ctlr) +{ + /* + * The controller may implement only the high-level SPI-memory like + * operations if it does not support regular SPI transfers, and this is + * valid use case. + * If ->mem_ops is NULL, we request that at least one of the + * ->transfer_xxx() method be implemented. + */ + if (ctlr->mem_ops) { + if (!ctlr->mem_ops->exec_op) + return -EINVAL; + } else if (!ctlr->transfer && !ctlr->transfer_one && + !ctlr->transfer_one_message) { + return -EINVAL; + } + + return 0; +} + /** * spi_register_controller - register SPI master or slave controller * @ctlr: initialized master, originally from spi_alloc_master() or @@ -2096,6 +2124,14 @@ int spi_register_controller(struct spi_controller *ctlr) if (!dev) return -ENODEV; + /* + * Make sure all necessary hooks are implemented before registering + * the SPI controller. + */ + status = spi_controller_check_ops(ctlr); + if (status) + return status; + if (!spi_controller_is_slave(ctlr)) { status = of_spi_register_master(ctlr); if (status) @@ -2161,10 +2197,14 @@ int spi_register_controller(struct spi_controller *ctlr) spi_controller_is_slave(ctlr) ? "slave" : "master", dev_name(&ctlr->dev)); - /* If we're using a queued driver, start the queue */ - if (ctlr->transfer) + /* + * If we're using a queued driver, start the queue. Note that we don't + * need the queueing logic if the driver is only supporting high-level + * memory operations. + */ + if (ctlr->transfer) { dev_info(dev, "controller is unqueued, this is deprecated\n"); - else { + } else if (ctlr->transfer_one || ctlr->transfer_one_message) { status = spi_controller_initialize_queue(ctlr); if (status) { device_del(&ctlr->dev); @@ -2894,6 +2934,13 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message) { struct spi_controller *ctlr = spi->controller; + /* + * Some controllers do not support doing regular SPI transfers. Return + * ENOTSUPP when this is the case. + */ + if (!ctlr->transfer) + return -ENOTSUPP; + message->spi = spi; SPI_STATISTICS_INCREMENT_FIELD(&ctlr->statistics, spi_async); @@ -3010,63 +3057,6 @@ int spi_async_locked(struct spi_device *spi, struct spi_message *message) } EXPORT_SYMBOL_GPL(spi_async_locked); - -int spi_flash_read(struct spi_device *spi, - struct spi_flash_read_message *msg) - -{ - struct spi_controller *master = spi->controller; - struct device *rx_dev = NULL; - int ret; - - if ((msg->opcode_nbits == SPI_NBITS_DUAL || - msg->addr_nbits == SPI_NBITS_DUAL) && - !(spi->mode & (SPI_TX_DUAL | SPI_TX_QUAD))) - return -EINVAL; - if ((msg->opcode_nbits == SPI_NBITS_QUAD || - msg->addr_nbits == SPI_NBITS_QUAD) && - !(spi->mode & SPI_TX_QUAD)) - return -EINVAL; - if (msg->data_nbits == SPI_NBITS_DUAL && - !(spi->mode & (SPI_RX_DUAL | SPI_RX_QUAD))) - return -EINVAL; - if (msg->data_nbits == SPI_NBITS_QUAD && - !(spi->mode & SPI_RX_QUAD)) - return -EINVAL; - - if (master->auto_runtime_pm) { - ret = pm_runtime_get_sync(master->dev.parent); - if (ret < 0) { - dev_err(&master->dev, "Failed to power device: %d\n", - ret); - return ret; - } - } - - mutex_lock(&master->bus_lock_mutex); - mutex_lock(&master->io_mutex); - if (master->dma_rx && master->spi_flash_can_dma(spi, msg)) { - rx_dev = master->dma_rx->device->dev; - ret = spi_map_buf(master, rx_dev, &msg->rx_sg, - msg->buf, msg->len, - DMA_FROM_DEVICE); - if (!ret) - msg->cur_msg_mapped = true; - } - ret = master->spi_flash_read(spi, msg); - if (msg->cur_msg_mapped) - spi_unmap_buf(master, rx_dev, &msg->rx_sg, - DMA_FROM_DEVICE); - mutex_unlock(&master->io_mutex); - mutex_unlock(&master->bus_lock_mutex); - - if (master->auto_runtime_pm) - pm_runtime_put(master->dev.parent); - - return ret; -} -EXPORT_SYMBOL_GPL(spi_flash_read); - /*-------------------------------------------------------------------------*/ /* Utility methods for SPI protocol drivers, layered on diff --git a/drivers/ssb/Kconfig b/drivers/ssb/Kconfig index 9371651d8017..c574dd210500 100644 --- a/drivers/ssb/Kconfig +++ b/drivers/ssb/Kconfig @@ -117,7 +117,7 @@ config SSB_SERIAL config SSB_DRIVER_PCICORE_POSSIBLE bool - depends on SSB_PCIHOST && SSB = y + depends on SSB_PCIHOST default y config SSB_DRIVER_PCICORE @@ -131,7 +131,7 @@ config SSB_DRIVER_PCICORE config SSB_PCICORE_HOSTMODE bool "Hostmode support for SSB PCI core" - depends on SSB_DRIVER_PCICORE && SSB_DRIVER_MIPS + depends on SSB_DRIVER_PCICORE && SSB_DRIVER_MIPS && SSB = y help PCIcore hostmode operation (external PCI bus). diff --git a/drivers/staging/comedi/drivers/serial2002.c b/drivers/staging/comedi/drivers/serial2002.c index b3f3b4a201af..5471b2212a62 100644 --- a/drivers/staging/comedi/drivers/serial2002.c +++ b/drivers/staging/comedi/drivers/serial2002.c @@ -113,7 +113,7 @@ static void serial2002_tty_read_poll_wait(struct file *f, int timeout) long elapsed; __poll_t mask; - mask = f->f_op->poll(f, &table.pt); + mask = vfs_poll(f, &table.pt); if (mask & (EPOLLRDNORM | EPOLLRDBAND | EPOLLIN | EPOLLHUP | EPOLLERR)) { break; @@ -136,7 +136,7 @@ static int serial2002_tty_read(struct file *f, int timeout) result = -1; if (!IS_ERR(f)) { - if (f->f_op->poll) { + if (file_can_poll(f)) { serial2002_tty_read_poll_wait(f, timeout); if (kernel_read(f, &ch, 1, &pos) == 1) diff --git a/drivers/staging/comedi/proc.c b/drivers/staging/comedi/proc.c index 50d38938ac6f..8bc8e42beb90 100644 --- a/drivers/staging/comedi/proc.c +++ b/drivers/staging/comedi/proc.c @@ -62,25 +62,9 @@ static int comedi_read(struct seq_file *m, void *v) return 0; } -/* - * seq_file wrappers for procfile show routines. - */ -static int comedi_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, comedi_read, NULL); -} - -static const struct file_operations comedi_proc_fops = { - .owner = THIS_MODULE, - .open = comedi_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - void __init comedi_proc_init(void) { - if (!proc_create("comedi", 0444, NULL, &comedi_proc_fops)) + if (!proc_create_single("comedi", 0444, NULL, comedi_read)) pr_warn("comedi: unable to create proc entry\n"); } diff --git a/drivers/staging/fwserial/fwserial.c b/drivers/staging/fwserial/fwserial.c index e8bfe5520bc7..fa0dd425b454 100644 --- a/drivers/staging/fwserial/fwserial.c +++ b/drivers/staging/fwserial/fwserial.c @@ -1506,11 +1506,6 @@ static int fwtty_debugfs_peers_show(struct seq_file *m, void *v) return 0; } -static int fwtty_proc_open(struct inode *inode, struct file *fp) -{ - return single_open(fp, fwtty_proc_show, NULL); -} - static int fwtty_stats_open(struct inode *inode, struct file *fp) { return single_open(fp, fwtty_debugfs_stats_show, inode->i_private); @@ -1537,14 +1532,6 @@ static const struct file_operations fwtty_peers_fops = { .release = single_release, }; -static const struct file_operations fwtty_proc_fops = { - .owner = THIS_MODULE, - .open = fwtty_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static const struct tty_port_operations fwtty_port_ops = { .dtr_rts = fwtty_port_dtr_rts, .carrier_raised = fwtty_port_carrier_raised, @@ -1570,7 +1557,7 @@ static const struct tty_operations fwtty_ops = { .tiocmget = fwtty_tiocmget, .tiocmset = fwtty_tiocmset, .get_icount = fwtty_get_icount, - .proc_fops = &fwtty_proc_fops, + .proc_show = fwtty_proc_show, }; static const struct tty_operations fwloop_ops = { diff --git a/drivers/staging/ipx/af_ipx.c b/drivers/staging/ipx/af_ipx.c index 5703dd176787..208b5c161631 100644 --- a/drivers/staging/ipx/af_ipx.c +++ b/drivers/staging/ipx/af_ipx.c @@ -1965,7 +1965,7 @@ static const struct proto_ops ipx_dgram_ops = { .socketpair = sock_no_socketpair, .accept = sock_no_accept, .getname = ipx_getname, - .poll = datagram_poll, + .poll_mask = datagram_poll_mask, .ioctl = ipx_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = ipx_compat_ioctl, diff --git a/drivers/staging/ipx/ipx_proc.c b/drivers/staging/ipx/ipx_proc.c index b9232e4e2ed4..360f0ad970de 100644 --- a/drivers/staging/ipx/ipx_proc.c +++ b/drivers/staging/ipx/ipx_proc.c @@ -244,42 +244,6 @@ static const struct seq_operations ipx_seq_socket_ops = { .show = ipx_seq_socket_show, }; -static int ipx_seq_route_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &ipx_seq_route_ops); -} - -static int ipx_seq_interface_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &ipx_seq_interface_ops); -} - -static int ipx_seq_socket_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &ipx_seq_socket_ops); -} - -static const struct file_operations ipx_seq_interface_fops = { - .open = ipx_seq_interface_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -static const struct file_operations ipx_seq_route_fops = { - .open = ipx_seq_route_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -static const struct file_operations ipx_seq_socket_fops = { - .open = ipx_seq_socket_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - static struct proc_dir_entry *ipx_proc_dir; int __init ipx_proc_init(void) @@ -291,16 +255,17 @@ int __init ipx_proc_init(void) if (!ipx_proc_dir) goto out; - p = proc_create("interface", S_IRUGO, - ipx_proc_dir, &ipx_seq_interface_fops); + p = proc_create_seq("interface", S_IRUGO, ipx_proc_dir, + &ipx_seq_interface_ops); if (!p) goto out_interface; - p = proc_create("route", S_IRUGO, ipx_proc_dir, &ipx_seq_route_fops); + p = proc_create_seq("route", S_IRUGO, ipx_proc_dir, &ipx_seq_route_ops); if (!p) goto out_route; - p = proc_create("socket", S_IRUGO, ipx_proc_dir, &ipx_seq_socket_fops); + p = proc_create_seq("socket", S_IRUGO, ipx_proc_dir, + &ipx_seq_socket_ops); if (!p) goto out_socket; diff --git a/drivers/staging/ncpfs/dir.c b/drivers/staging/ncpfs/dir.c index 0c57c5c5d40a..072bcb12898f 100644 --- a/drivers/staging/ncpfs/dir.c +++ b/drivers/staging/ncpfs/dir.c @@ -823,12 +823,11 @@ static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, unsig struct ncp_server *server = NCP_SERVER(dir); struct inode *inode = NULL; struct ncp_entry_info finfo; - int error, res, len; + int res, len; __u8 __name[NCP_MAXPATHLEN + 1]; - error = -EIO; if (!ncp_conn_valid(server)) - goto finished; + return ERR_PTR(-EIO); ncp_vdbg("server lookup for %pd2\n", dentry); @@ -847,31 +846,20 @@ static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, unsig res = ncp_obtain_info(server, dir, __name, &(finfo.i)); } ncp_vdbg("looked for %pd2, res=%d\n", dentry, res); - /* - * If we didn't find an entry, make a negative dentry. - */ - if (res) - goto add_entry; - - /* - * Create an inode for the entry. - */ - finfo.opened = 0; - finfo.ino = iunique(dir->i_sb, 2); - finfo.volume = finfo.i.volNumber; - error = -EACCES; - inode = ncp_iget(dir->i_sb, &finfo); - - if (inode) { - ncp_new_dentry(dentry); -add_entry: - d_add(dentry, inode); - error = 0; + if (!res) { + /* + * Entry found; create an inode for it. + */ + finfo.opened = 0; + finfo.ino = iunique(dir->i_sb, 2); + finfo.volume = finfo.i.volNumber; + inode = ncp_iget(dir->i_sb, &finfo); + if (unlikely(!inode)) + inode = ERR_PTR(-EACCES); + else + ncp_new_dentry(dentry); } - -finished: - ncp_vdbg("result=%d\n", error); - return ERR_PTR(error); + return d_splice_alias(inode, dentry); } /* diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c index d607c59761cf..7a0dbc0fa18e 100644 --- a/drivers/staging/rtl8192u/r8192U_core.c +++ b/drivers/staging/rtl8192u/r8192U_core.c @@ -646,64 +646,25 @@ static void rtl8192_proc_module_init(void) rtl8192_proc = proc_mkdir(RTL819xU_MODULE_NAME, init_net.proc_net); } -/* - * seq_file wrappers for procfile show routines. - */ -static int rtl8192_proc_open(struct inode *inode, struct file *file) -{ - struct net_device *dev = proc_get_parent_data(inode); - int (*show)(struct seq_file *, void *) = PDE_DATA(inode); - - return single_open(file, show, dev); -} - -static const struct file_operations rtl8192_proc_fops = { - .open = rtl8192_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -/* - * Table of proc files we need to create. - */ -struct rtl8192_proc_file { - char name[12]; - int (*show)(struct seq_file *, void *); -}; - -static const struct rtl8192_proc_file rtl8192_proc_files[] = { - { "stats-rx", &proc_get_stats_rx }, - { "stats-tx", &proc_get_stats_tx }, - { "stats-ap", &proc_get_stats_ap }, - { "registers", &proc_get_registers }, - { "" } -}; - static void rtl8192_proc_init_one(struct net_device *dev) { - const struct rtl8192_proc_file *f; struct proc_dir_entry *dir; - if (rtl8192_proc) { - dir = proc_mkdir_data(dev->name, 0, rtl8192_proc, dev); - if (!dir) { - RT_TRACE(COMP_ERR, - "Unable to initialize /proc/net/rtl8192/%s\n", - dev->name); - return; - } + if (!rtl8192_proc) + return; - for (f = rtl8192_proc_files; f->name[0]; f++) { - if (!proc_create_data(f->name, S_IFREG | S_IRUGO, dir, - &rtl8192_proc_fops, f->show)) { - RT_TRACE(COMP_ERR, - "Unable to initialize /proc/net/rtl8192/%s/%s\n", - dev->name, f->name); - return; - } - } - } + dir = proc_mkdir_data(dev->name, 0, rtl8192_proc, dev); + if (!dir) + return; + + proc_create_single("stats-rx", S_IFREG | S_IRUGO, dir, + proc_get_stats_rx); + proc_create_single("stats-tx", S_IFREG | S_IRUGO, dir, + proc_get_stats_tx); + proc_create_single("stats-ap", S_IFREG | S_IRUGO, dir, + proc_get_stats_ap); + proc_create_single("registers", S_IFREG | S_IRUGO, dir, + proc_get_registers); } static void rtl8192_proc_remove_one(struct net_device *dev) diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 60429011292a..ce1321a5cb7b 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -94,8 +94,8 @@ static int iblock_configure_device(struct se_device *dev) return -EINVAL; } - ib_dev->ibd_bio_set = bioset_create(IBLOCK_BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS); - if (!ib_dev->ibd_bio_set) { + ret = bioset_init(&ib_dev->ibd_bio_set, IBLOCK_BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS); + if (ret) { pr_err("IBLOCK: Unable to create bioset\n"); goto out; } @@ -141,7 +141,7 @@ static int iblock_configure_device(struct se_device *dev) bi = bdev_get_integrity(bd); if (bi) { - struct bio_set *bs = ib_dev->ibd_bio_set; + struct bio_set *bs = &ib_dev->ibd_bio_set; if (!strcmp(bi->profile->name, "T10-DIF-TYPE3-IP") || !strcmp(bi->profile->name, "T10-DIF-TYPE1-IP")) { @@ -164,7 +164,7 @@ static int iblock_configure_device(struct se_device *dev) goto out_blkdev_put; } pr_debug("IBLOCK setup BIP bs->bio_integrity_pool: %p\n", - bs->bio_integrity_pool); + &bs->bio_integrity_pool); } dev->dev_attrib.hw_pi_prot_type = dev->dev_attrib.pi_prot_type; } @@ -174,8 +174,7 @@ static int iblock_configure_device(struct se_device *dev) out_blkdev_put: blkdev_put(ib_dev->ibd_bd, FMODE_WRITE|FMODE_READ|FMODE_EXCL); out_free_bioset: - bioset_free(ib_dev->ibd_bio_set); - ib_dev->ibd_bio_set = NULL; + bioset_exit(&ib_dev->ibd_bio_set); out: return ret; } @@ -199,8 +198,7 @@ static void iblock_destroy_device(struct se_device *dev) if (ib_dev->ibd_bd != NULL) blkdev_put(ib_dev->ibd_bd, FMODE_WRITE|FMODE_READ|FMODE_EXCL); - if (ib_dev->ibd_bio_set != NULL) - bioset_free(ib_dev->ibd_bio_set); + bioset_exit(&ib_dev->ibd_bio_set); } static unsigned long long iblock_emulate_read_cap_with_block_size( @@ -332,7 +330,7 @@ iblock_get_bio(struct se_cmd *cmd, sector_t lba, u32 sg_num, int op, if (sg_num > BIO_MAX_PAGES) sg_num = BIO_MAX_PAGES; - bio = bio_alloc_bioset(GFP_NOIO, sg_num, ib_dev->ibd_bio_set); + bio = bio_alloc_bioset(GFP_NOIO, sg_num, &ib_dev->ibd_bio_set); if (!bio) { pr_err("Unable to allocate memory for bio\n"); return NULL; diff --git a/drivers/target/target_core_iblock.h b/drivers/target/target_core_iblock.h index b4aeb2584ad4..9cc3843404d4 100644 --- a/drivers/target/target_core_iblock.h +++ b/drivers/target/target_core_iblock.h @@ -22,7 +22,7 @@ struct iblock_dev { struct se_device dev; unsigned char ibd_udev_path[SE_UDEV_PATH_LEN]; u32 ibd_flags; - struct bio_set *ibd_bio_set; + struct bio_set ibd_bio_set; struct block_device *ibd_bd; bool ibd_readonly; } ____cacheline_aligned; diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 6cb933ecc084..668934ea74cb 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -986,8 +986,7 @@ pscsi_execute_cmd(struct se_cmd *cmd) req = blk_get_request(pdv->pdv_sd->request_queue, cmd->data_direction == DMA_TO_DEVICE ? - REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, - GFP_KERNEL); + REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, 0); if (IS_ERR(req)) { pr_err("PSCSI: blk_get_request() failed\n"); ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 4ad89ea71a70..4f26bdc3d1dc 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -2121,6 +2121,8 @@ static ssize_t tcmu_qfull_time_out_store(struct config_item *item, if (val >= 0) { udev->qfull_time_out = val * MSEC_PER_SEC; + } else if (val == -1) { + udev->qfull_time_out = val; } else { printk(KERN_ERR "Invalid qfull timeout value %d\n", val); return -EINVAL; diff --git a/drivers/thunderbolt/icm.c b/drivers/thunderbolt/icm.c index 2d2ceda9aa26..500911f16498 100644 --- a/drivers/thunderbolt/icm.c +++ b/drivers/thunderbolt/icm.c @@ -1255,7 +1255,7 @@ static int icm_ar_get_boot_acl(struct tb *tb, uuid_t *uuids, size_t nuuids) /* Map empty entries to null UUID */ uuid[0] = 0; uuid[1] = 0; - } else { + } else if (uuid[0] != 0 || uuid[1] != 0) { /* Upper two DWs are always one's */ uuid[2] = 0xffffffff; uuid[3] = 0xffffffff; diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 32d7ce430b02..34dead614149 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -1566,19 +1566,6 @@ static int rs_proc_show(struct seq_file *m, void *v) return 0; } -static int rs_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, rs_proc_show, NULL); -} - -static const struct file_operations rs_proc_fops = { - .owner = THIS_MODULE, - .open = rs_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - /* * --------------------------------------------------------------------- * rs_init() and friends @@ -1620,7 +1607,7 @@ static const struct tty_operations serial_ops = { .tiocmget = rs_tiocmget, .tiocmset = rs_tiocmset, .get_icount = rs_get_icount, - .proc_fops = &rs_proc_fops, + .proc_show = rs_proc_show, }; static int amiga_carrier_raised(struct tty_port *port) diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c index cf0bde3bb927..6d3c58051ce3 100644 --- a/drivers/tty/cyclades.c +++ b/drivers/tty/cyclades.c @@ -3972,19 +3972,6 @@ static int cyclades_proc_show(struct seq_file *m, void *v) return 0; } -static int cyclades_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, cyclades_proc_show, NULL); -} - -static const struct file_operations cyclades_proc_fops = { - .owner = THIS_MODULE, - .open = cyclades_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - /* The serial driver boot-time initialization code! Hardware I/O ports are mapped to character special devices on a first found, first allocated manner. That is, this code searches @@ -4024,7 +4011,7 @@ static const struct tty_operations cy_ops = { .tiocmget = cy_tiocmget, .tiocmset = cy_tiocmset, .get_icount = cy_get_icount, - .proc_fops = &cyclades_proc_fops, + .proc_show = cyclades_proc_show, }; static int __init cy_init(void) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 0466f9f08a91..6ff9405954a6 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1829,19 +1829,6 @@ static int uart_proc_show(struct seq_file *m, void *v) uart_line_info(m, drv, i); return 0; } - -static int uart_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, uart_proc_show, PDE_DATA(inode)); -} - -static const struct file_operations uart_proc_fops = { - .owner = THIS_MODULE, - .open = uart_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; #endif #if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL) @@ -2415,7 +2402,7 @@ static const struct tty_operations uart_ops = { .break_ctl = uart_break_ctl, .wait_until_sent= uart_wait_until_sent, #ifdef CONFIG_PROC_FS - .proc_fops = &uart_proc_fops, + .proc_show = uart_proc_show, #endif .tiocmget = uart_tiocmget, .tiocmset = uart_tiocmset, diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index 3c4ad71f261d..fbdf4d01c6a9 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -3534,19 +3534,6 @@ static int mgsl_proc_show(struct seq_file *m, void *v) return 0; } -static int mgsl_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, mgsl_proc_show, NULL); -} - -static const struct file_operations mgsl_proc_fops = { - .owner = THIS_MODULE, - .open = mgsl_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - /* mgsl_allocate_dma_buffers() * * Allocate and format DMA buffers (ISA adapter) @@ -4298,7 +4285,7 @@ static const struct tty_operations mgsl_ops = { .tiocmget = tiocmget, .tiocmset = tiocmset, .get_icount = msgl_get_icount, - .proc_fops = &mgsl_proc_fops, + .proc_show = mgsl_proc_show, }; /* diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index 255c49687877..a94086597ebd 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -1316,19 +1316,6 @@ static int synclink_gt_proc_show(struct seq_file *m, void *v) return 0; } -static int synclink_gt_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, synclink_gt_proc_show, NULL); -} - -static const struct file_operations synclink_gt_proc_fops = { - .owner = THIS_MODULE, - .open = synclink_gt_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - /* * return count of bytes in transmit buffer */ @@ -3721,7 +3708,7 @@ static const struct tty_operations ops = { .tiocmget = tiocmget, .tiocmset = tiocmset, .get_icount = get_icount, - .proc_fops = &synclink_gt_proc_fops, + .proc_show = synclink_gt_proc_show, }; static void slgt_cleanup(void) diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index 75f11ce1f0a1..1e4d5b9c981a 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c @@ -1421,19 +1421,6 @@ static int synclinkmp_proc_show(struct seq_file *m, void *v) return 0; } -static int synclinkmp_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, synclinkmp_proc_show, NULL); -} - -static const struct file_operations synclinkmp_proc_fops = { - .owner = THIS_MODULE, - .open = synclinkmp_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - /* Return the count of bytes in transmit buffer */ static int chars_in_buffer(struct tty_struct *tty) @@ -3899,7 +3886,7 @@ static const struct tty_operations ops = { .tiocmget = tiocmget, .tiocmset = tiocmset, .get_icount = get_icount, - .proc_fops = &synclinkmp_proc_fops, + .proc_show = synclinkmp_proc_show, }; diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index fb7329ab2b37..fc4c97cae01e 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -229,26 +229,13 @@ static int tty_ldiscs_seq_show(struct seq_file *m, void *v) return 0; } -static const struct seq_operations tty_ldiscs_seq_ops = { +const struct seq_operations tty_ldiscs_seq_ops = { .start = tty_ldiscs_seq_start, .next = tty_ldiscs_seq_next, .stop = tty_ldiscs_seq_stop, .show = tty_ldiscs_seq_show, }; -static int proc_tty_ldiscs_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &tty_ldiscs_seq_ops); -} - -const struct file_operations tty_ldiscs_proc_fops = { - .owner = THIS_MODULE, - .open = proc_tty_ldiscs_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - /** * tty_ldisc_ref_wait - wait for the tty ldisc * @tty: tty device diff --git a/drivers/usb/gadget/udc/at91_udc.c b/drivers/usb/gadget/udc/at91_udc.c index ad743a8493be..03959dc86cfd 100644 --- a/drivers/usb/gadget/udc/at91_udc.c +++ b/drivers/usb/gadget/udc/at91_udc.c @@ -234,22 +234,10 @@ static int proc_udc_show(struct seq_file *s, void *unused) return 0; } -static int proc_udc_open(struct inode *inode, struct file *file) -{ - return single_open(file, proc_udc_show, PDE_DATA(inode)); -} - -static const struct file_operations proc_ops = { - .owner = THIS_MODULE, - .open = proc_udc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static void create_debug_file(struct at91_udc *udc) { - udc->pde = proc_create_data(debug_filename, 0, NULL, &proc_ops, udc); + udc->pde = proc_create_single_data(debug_filename, 0, NULL, + proc_udc_show, udc); } static void remove_debug_file(struct at91_udc *udc) diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c index a3c092b4db20..9a3f7db26a5e 100644 --- a/drivers/usb/gadget/udc/fsl_udc_core.c +++ b/drivers/usb/gadget/udc/fsl_udc_core.c @@ -2208,22 +2208,8 @@ static int fsl_proc_read(struct seq_file *m, void *v) return 0; } -/* - * seq_file wrappers for procfile show routines. - */ -static int fsl_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, fsl_proc_read, NULL); -} - -static const struct file_operations fsl_proc_fops = { - .open = fsl_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -#define create_proc_file() proc_create(proc_filename, 0, NULL, &fsl_proc_fops) +#define create_proc_file() \ + proc_create_single(proc_filename, 0, NULL, fsl_proc_read) #define remove_proc_file() remove_proc_entry(proc_filename, NULL) #else /* !CONFIG_USB_GADGET_DEBUG_FILES */ diff --git a/drivers/usb/gadget/udc/goku_udc.c b/drivers/usb/gadget/udc/goku_udc.c index 4504d0b202db..c3721225b61e 100644 --- a/drivers/usb/gadget/udc/goku_udc.c +++ b/drivers/usb/gadget/udc/goku_udc.c @@ -1241,22 +1241,6 @@ done: local_irq_restore(flags); return 0; } - -/* - * seq_file wrappers for procfile show routines. - */ -static int udc_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, udc_proc_read, PDE_DATA(file_inode(file))); -} - -static const struct file_operations udc_proc_fops = { - .open = udc_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - #endif /* CONFIG_USB_GADGET_DEBUG_FILES */ /*-------------------------------------------------------------------------*/ @@ -1826,7 +1810,7 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id) #ifdef CONFIG_USB_GADGET_DEBUG_FILES - proc_create_data(proc_node_name, 0, NULL, &udc_proc_fops, dev); + proc_create_single_data(proc_node_name, 0, NULL, udc_proc_read, dev); #endif retval = usb_add_gadget_udc_release(&pdev->dev, &dev->gadget, diff --git a/drivers/usb/gadget/udc/omap_udc.c b/drivers/usb/gadget/udc/omap_udc.c index dc35a54bad90..3a16431da321 100644 --- a/drivers/usb/gadget/udc/omap_udc.c +++ b/drivers/usb/gadget/udc/omap_udc.c @@ -2432,22 +2432,9 @@ static int proc_udc_show(struct seq_file *s, void *_) return 0; } -static int proc_udc_open(struct inode *inode, struct file *file) -{ - return single_open(file, proc_udc_show, NULL); -} - -static const struct file_operations proc_ops = { - .owner = THIS_MODULE, - .open = proc_udc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static void create_proc_file(void) { - proc_create(proc_filename, 0, NULL, &proc_ops); + proc_create_single(proc_filename, 0, NULL, proc_udc_show); } static void remove_proc_file(void) diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 44ecf0e2be9d..f7aaa7f079e1 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -476,19 +476,6 @@ static int serial_proc_show(struct seq_file *m, void *v) return 0; } -static int serial_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, serial_proc_show, NULL); -} - -static const struct file_operations serial_proc_fops = { - .owner = THIS_MODULE, - .open = serial_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static int serial_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; @@ -1192,7 +1179,7 @@ static const struct tty_operations serial_ops = { .get_icount = serial_get_icount, .cleanup = serial_cleanup, .install = serial_install, - .proc_fops = &serial_proc_fops, + .proc_show = serial_proc_show, }; diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c index 5c212bf29640..3c082451ab1a 100644 --- a/drivers/vfio/vfio_iommu_type1.c +++ b/drivers/vfio/vfio_iommu_type1.c @@ -404,6 +404,7 @@ static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr, { unsigned long pfn = 0; long ret, pinned = 0, lock_acct = 0; + bool rsvd; dma_addr_t iova = vaddr - dma->vaddr + dma->iova; /* This code path is only user initiated */ @@ -414,23 +415,14 @@ static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr, if (ret) return ret; - if (is_invalid_reserved_pfn(*pfn_base)) { - struct vm_area_struct *vma; - - down_read(¤t->mm->mmap_sem); - vma = find_vma_intersection(current->mm, vaddr, vaddr + 1); - pinned = min_t(long, npage, vma_pages(vma)); - up_read(¤t->mm->mmap_sem); - return pinned; - } - pinned++; + rsvd = is_invalid_reserved_pfn(*pfn_base); /* * Reserved pages aren't counted against the user, externally pinned * pages are already counted against the user. */ - if (!vfio_find_vpfn(dma, iova)) { + if (!rsvd && !vfio_find_vpfn(dma, iova)) { if (!lock_cap && current->mm->locked_vm + 1 > limit) { put_pfn(*pfn_base, dma->prot); pr_warn("%s: RLIMIT_MEMLOCK (%ld) exceeded\n", __func__, @@ -450,12 +442,13 @@ static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr, if (ret) break; - if (pfn != *pfn_base + pinned) { + if (pfn != *pfn_base + pinned || + rsvd != is_invalid_reserved_pfn(pfn)) { put_pfn(pfn, dma->prot); break; } - if (!vfio_find_vpfn(dma, iova)) { + if (!rsvd && !vfio_find_vpfn(dma, iova)) { if (!lock_cap && current->mm->locked_vm + lock_acct + 1 > limit) { put_pfn(pfn, dma->prot); @@ -473,8 +466,10 @@ out: unpin_out: if (ret) { - for (pfn = *pfn_base ; pinned ; pfn++, pinned--) - put_pfn(pfn, dma->prot); + if (!rsvd) { + for (pfn = *pfn_base ; pinned ; pfn++, pinned--) + put_pfn(pfn, dma->prot); + } return ret; } diff --git a/drivers/vfio/virqfd.c b/drivers/vfio/virqfd.c index 085700f1be10..2a1be859ee71 100644 --- a/drivers/vfio/virqfd.c +++ b/drivers/vfio/virqfd.c @@ -166,7 +166,7 @@ int vfio_virqfd_enable(void *opaque, init_waitqueue_func_entry(&virqfd->wait, virqfd_wakeup); init_poll_funcptr(&virqfd->pt, virqfd_ptable_queue_proc); - events = irqfd.file->f_op->poll(irqfd.file, &virqfd->pt); + events = vfs_poll(irqfd.file, &virqfd->pt); /* * Check if there was an event already pending on the eventfd diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 986058a57917..eeaf6739215f 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -105,7 +105,9 @@ struct vhost_net_virtqueue { /* vhost zerocopy support fields below: */ /* last used idx for outstanding DMA zerocopy buffers */ int upend_idx; - /* first used idx for DMA done zerocopy buffers */ + /* For TX, first used idx for DMA done zerocopy buffers + * For RX, number of batched heads + */ int done_idx; /* an array of userspace buffers info */ struct ubuf_info *ubuf_info; @@ -626,6 +628,18 @@ static int sk_has_rx_data(struct sock *sk) return skb_queue_empty(&sk->sk_receive_queue); } +static void vhost_rx_signal_used(struct vhost_net_virtqueue *nvq) +{ + struct vhost_virtqueue *vq = &nvq->vq; + struct vhost_dev *dev = vq->dev; + + if (!nvq->done_idx) + return; + + vhost_add_used_and_signal_n(dev, vq, vq->heads, nvq->done_idx); + nvq->done_idx = 0; +} + static int vhost_net_rx_peek_head_len(struct vhost_net *net, struct sock *sk) { struct vhost_net_virtqueue *rvq = &net->vqs[VHOST_NET_VQ_RX]; @@ -635,6 +649,8 @@ static int vhost_net_rx_peek_head_len(struct vhost_net *net, struct sock *sk) int len = peek_head_len(rvq, sk); if (!len && vq->busyloop_timeout) { + /* Flush batched heads first */ + vhost_rx_signal_used(rvq); /* Both tx vq and rx socket were polled here */ mutex_lock_nested(&vq->mutex, 1); vhost_disable_notify(&net->dev, vq); @@ -762,7 +778,7 @@ static void handle_rx(struct vhost_net *net) }; size_t total_len = 0; int err, mergeable; - s16 headcount, nheads = 0; + s16 headcount; size_t vhost_hlen, sock_hlen; size_t vhost_len, sock_len; struct socket *sock; @@ -790,8 +806,8 @@ static void handle_rx(struct vhost_net *net) while ((sock_len = vhost_net_rx_peek_head_len(net, sock->sk))) { sock_len += sock_hlen; vhost_len = sock_len + vhost_hlen; - headcount = get_rx_bufs(vq, vq->heads + nheads, vhost_len, - &in, vq_log, &log, + headcount = get_rx_bufs(vq, vq->heads + nvq->done_idx, + vhost_len, &in, vq_log, &log, likely(mergeable) ? UIO_MAXIOV : 1); /* On error, stop handling until the next kick. */ if (unlikely(headcount < 0)) @@ -862,12 +878,9 @@ static void handle_rx(struct vhost_net *net) vhost_discard_vq_desc(vq, headcount); goto out; } - nheads += headcount; - if (nheads > VHOST_RX_BATCH) { - vhost_add_used_and_signal_n(&net->dev, vq, vq->heads, - nheads); - nheads = 0; - } + nvq->done_idx += headcount; + if (nvq->done_idx > VHOST_RX_BATCH) + vhost_rx_signal_used(nvq); if (unlikely(vq_log)) vhost_log_write(vq, vq_log, log, vhost_len); total_len += vhost_len; @@ -878,9 +891,7 @@ static void handle_rx(struct vhost_net *net) } vhost_net_enable_vq(net, vq); out: - if (nheads) - vhost_add_used_and_signal_n(&net->dev, vq, vq->heads, - nheads); + vhost_rx_signal_used(nvq); mutex_unlock(&vq->mutex); } diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index f3bd8e941224..895eaa25807c 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -208,7 +208,7 @@ int vhost_poll_start(struct vhost_poll *poll, struct file *file) if (poll->wqh) return 0; - mask = file->f_op->poll(file, &poll->table); + mask = vfs_poll(file, &poll->table); if (mask) vhost_poll_wakeup(&poll->wait, 0, 0, poll_to_key(mask)); if (mask & EPOLLERR) { @@ -981,6 +981,7 @@ static int vhost_process_iotlb_msg(struct vhost_dev *dev, { int ret = 0; + mutex_lock(&dev->mutex); vhost_dev_lock_vqs(dev); switch (msg->type) { case VHOST_IOTLB_UPDATE: @@ -1016,6 +1017,8 @@ static int vhost_process_iotlb_msg(struct vhost_dev *dev, } vhost_dev_unlock_vqs(dev); + mutex_unlock(&dev->mutex); + return ret; } ssize_t vhost_chr_write_iter(struct vhost_dev *dev, diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index f741ba8df01b..924d0730ffe2 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -713,19 +713,6 @@ static const struct seq_operations proc_fb_seq_ops = { .show = fb_seq_show, }; -static int proc_fb_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &proc_fb_seq_ops); -} - -static const struct file_operations fb_proc_fops = { - .owner = THIS_MODULE, - .open = proc_fb_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - /* * We hold a reference to the fb_info in file->private_data, * but if the current registered fb has changed, we don't @@ -1877,7 +1864,7 @@ fbmem_init(void) { int ret; - if (!proc_create("fb", 0, NULL, &fb_proc_fops)) + if (!proc_create_seq("fb", 0, NULL, &proc_fb_seq_ops)) return -ENOMEM; ret = register_chrdev(FB_MAJOR, "fb", &fb_fops); diff --git a/drivers/video/fbdev/via/viafbdev.c b/drivers/video/fbdev/via/viafbdev.c index badee04ef496..9b45125988fb 100644 --- a/drivers/video/fbdev/via/viafbdev.c +++ b/drivers/video/fbdev/via/viafbdev.c @@ -1475,19 +1475,6 @@ static int viafb_sup_odev_proc_show(struct seq_file *m, void *v) return 0; } -static int viafb_sup_odev_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, viafb_sup_odev_proc_show, NULL); -} - -static const struct file_operations viafb_sup_odev_proc_fops = { - .owner = THIS_MODULE, - .open = viafb_sup_odev_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static ssize_t odev_update(const char __user *buffer, size_t count, u32 *odev) { char buf[64], *ptr = buf; @@ -1616,8 +1603,8 @@ static void viafb_init_proc(struct viafb_shared *shared) &viafb_vt1636_proc_fops); #endif /* CONFIG_FB_VIA_DIRECT_PROCFS */ - proc_create("supported_output_devices", 0, viafb_entry, - &viafb_sup_odev_proc_fops); + proc_create_single("supported_output_devices", 0, viafb_entry, + viafb_sup_odev_proc_show); iga1_entry = proc_mkdir("iga1", viafb_entry); shared->iga1_proc_entry = iga1_entry; proc_create("output_devices", 0, iga1_entry, diff --git a/drivers/w1/w1_io.c b/drivers/w1/w1_io.c index 075d120e7b88..0364d3329c52 100644 --- a/drivers/w1/w1_io.c +++ b/drivers/w1/w1_io.c @@ -194,6 +194,7 @@ static u8 w1_read_bit(struct w1_master *dev) * bit 0 = id_bit * bit 1 = comp_bit * bit 2 = dir_taken + * * If both bits 0 & 1 are set, the search should be restarted. * * Return: bit fields - see above diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c index e1c60899fdbc..a6f9ba85dc4b 100644 --- a/drivers/xen/swiotlb-xen.c +++ b/drivers/xen/swiotlb-xen.c @@ -351,7 +351,7 @@ xen_swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr, * physical address */ phys = xen_bus_to_phys(dev_addr); - if (((dev_addr + size - 1 > dma_mask)) || + if (((dev_addr + size - 1 <= dma_mask)) || range_straddles_page_boundary(phys, size)) xen_destroy_contiguous_region(phys, order); diff --git a/drivers/zorro/proc.c b/drivers/zorro/proc.c index df05a26ab8d8..2e4ca4dc0960 100644 --- a/drivers/zorro/proc.c +++ b/drivers/zorro/proc.c @@ -96,19 +96,6 @@ static const struct seq_operations zorro_devices_seq_ops = { .show = zorro_seq_show, }; -static int zorro_devices_proc_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &zorro_devices_seq_ops); -} - -static const struct file_operations zorro_devices_proc_fops = { - .owner = THIS_MODULE, - .open = zorro_devices_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - static struct proc_dir_entry *proc_bus_zorro_dir; static int __init zorro_proc_attach_device(unsigned int slot) @@ -132,8 +119,8 @@ static int __init zorro_proc_init(void) if (MACH_IS_AMIGA && AMIGAHW_PRESENT(ZORRO)) { proc_bus_zorro_dir = proc_mkdir("bus/zorro", NULL); - proc_create("devices", 0, proc_bus_zorro_dir, - &zorro_devices_proc_fops); + proc_create_seq("devices", 0, proc_bus_zorro_dir, + &zorro_devices_seq_ops); for (slot = 0; slot < zorro_num_autocon; slot++) zorro_proc_attach_device(slot); } diff --git a/drivers/zorro/zorro.c b/drivers/zorro/zorro.c index 47728477297e..67fa900572a9 100644 --- a/drivers/zorro/zorro.c +++ b/drivers/zorro/zorro.c @@ -101,6 +101,7 @@ static void __init mark_region(unsigned long start, unsigned long end, end = end > Z2RAM_END ? Z2RAM_SIZE : end-Z2RAM_START; while (start < end) { u32 chunk = start>>Z2RAM_CHUNKSHIFT; + if (flag) set_bit(chunk, zorro_unused_z2ram); else @@ -117,6 +118,7 @@ static struct resource __init *zorro_find_parent_resource( for (i = 0; i < bridge->num_resources; i++) { struct resource *r = &bridge->resource[i]; + if (zorro_resource_start(z) >= r->start && zorro_resource_end(z) <= r->end) return r; @@ -168,6 +170,7 @@ static int __init amiga_zorro_probe(struct platform_device *pdev) if (z->id == ZORRO_PROD_GVP_EPC_BASE) { /* GVP quirk */ unsigned long magic = zi->boardaddr + 0x8000; + z->id |= *(u16 *)ZTWO_VADDR(magic) & GVP_PRODMASK; } z->slotaddr = zi->slotaddr; |