diff options
Diffstat (limited to 'drivers')
1306 files changed, 17457 insertions, 9226 deletions
diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index cb6ac5c65c2e..38a286975c31 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -233,11 +233,13 @@ static const struct lpss_device_desc lpt_sdio_dev_desc = { static const struct lpss_device_desc byt_pwm_dev_desc = { .flags = LPSS_SAVE_CTX, + .prv_offset = 0x800, .setup = byt_pwm_setup, }; static const struct lpss_device_desc bsw_pwm_dev_desc = { .flags = LPSS_SAVE_CTX | LPSS_NO_D3_DELAY, + .prv_offset = 0x800, .setup = bsw_pwm_setup, }; diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c index 88cd949003f3..eaa60c94205a 100644 --- a/drivers/acpi/acpi_platform.c +++ b/drivers/acpi/acpi_platform.c @@ -82,7 +82,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev, if (count < 0) { return NULL; } else if (count > 0) { - resources = kzalloc(count * sizeof(struct resource), + resources = kcalloc(count, sizeof(struct resource), GFP_KERNEL); if (!resources) { dev_err(&adev->dev, "No memory for resources\n"); diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index 2f2e737be0f8..f0b52266b3ac 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -832,8 +832,9 @@ int acpi_video_get_levels(struct acpi_device *device, * in order to account for buggy BIOS which don't export the first two * special levels (see below) */ - br->levels = kmalloc((obj->package.count + ACPI_VIDEO_FIRST_LEVEL) * - sizeof(*br->levels), GFP_KERNEL); + br->levels = kmalloc_array(obj->package.count + ACPI_VIDEO_FIRST_LEVEL, + sizeof(*br->levels), + GFP_KERNEL); if (!br->levels) { result = -ENOMEM; goto out_free; diff --git a/drivers/acpi/acpica/dbnames.c b/drivers/acpi/acpica/dbnames.c index dc94de91033e..992bd7b92540 100644 --- a/drivers/acpi/acpica/dbnames.c +++ b/drivers/acpi/acpica/dbnames.c @@ -322,6 +322,7 @@ acpi_db_walk_and_match_name(acpi_handle obj_handle, acpi_os_printf("Could Not get pathname for object %p\n", obj_handle); } else { + info.count = 0; info.owner_id = ACPI_OWNER_ID_MAX; info.debug_level = ACPI_UINT32_MAX; info.display_type = ACPI_DISPLAY_SUMMARY | ACPI_DISPLAY_SHORT; diff --git a/drivers/acpi/acpica/dbobject.c b/drivers/acpi/acpica/dbobject.c index 58c3253b533a..a1c76bf21122 100644 --- a/drivers/acpi/acpica/dbobject.c +++ b/drivers/acpi/acpica/dbobject.c @@ -35,6 +35,15 @@ void acpi_db_dump_method_info(acpi_status status, struct acpi_walk_state *walk_state) { struct acpi_thread_state *thread; + struct acpi_namespace_node *node; + + node = walk_state->method_node; + + /* There are no locals or arguments for the module-level code case */ + + if (node == acpi_gbl_root_node) { + return; + } /* Ignore control codes, they are not errors */ @@ -384,8 +393,14 @@ void acpi_db_decode_locals(struct acpi_walk_state *walk_state) struct acpi_namespace_node *node; u8 display_locals = FALSE; - obj_desc = walk_state->method_desc; node = walk_state->method_node; + obj_desc = walk_state->method_desc; + + /* There are no locals for the module-level code case */ + + if (node == acpi_gbl_root_node) { + return; + } if (!node) { acpi_os_printf @@ -452,6 +467,12 @@ void acpi_db_decode_arguments(struct acpi_walk_state *walk_state) node = walk_state->method_node; obj_desc = walk_state->method_desc; + /* There are no arguments for the module-level code case */ + + if (node == acpi_gbl_root_node) { + return; + } + if (!node) { acpi_os_printf ("No method node (Executing subtree for buffer or opregion)\n"); diff --git a/drivers/acpi/acpica/dsdebug.c b/drivers/acpi/acpica/dsdebug.c index 70a2fca60306..9d33f0bb2885 100644 --- a/drivers/acpi/acpica/dsdebug.c +++ b/drivers/acpi/acpica/dsdebug.c @@ -162,9 +162,15 @@ acpi_ds_dump_method_stack(acpi_status status, op->common.next = NULL; #ifdef ACPI_DISASSEMBLER - acpi_os_printf("Failed at "); - acpi_dm_disassemble(next_walk_state, op, - ACPI_UINT32_MAX); + if (walk_state->method_node != + acpi_gbl_root_node) { + + /* More verbose if not module-level code */ + + acpi_os_printf("Failed at "); + acpi_dm_disassemble(next_walk_state, op, + ACPI_UINT32_MAX); + } #endif op->common.next = next; } diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index f85c6f3271f6..2373a7492151 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -490,6 +490,17 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle) ACPI_WARNING((AE_INFO, "Received request to unload an ACPI table")); /* + * May 2018: Unload is no longer supported for the following reasons: + * 1) A correct implementation on some hosts may not be possible. + * 2) Other ACPI implementations do not correctly/fully support it. + * 3) It requires host device driver support which does not exist. + * (To properly support namespace unload out from underneath.) + * 4) This AML operator has never been seen in the field. + */ + ACPI_EXCEPTION((AE_INFO, AE_NOT_IMPLEMENTED, + "AML Unload operator is not supported")); + + /* * Validate the handle * Although the handle is partially validated in acpi_ex_reconfiguration() * when it calls acpi_ex_resolve_operands(), the handle is more completely diff --git a/drivers/acpi/acpica/nsdump.c b/drivers/acpi/acpica/nsdump.c index 4bdbd1d8431b..90ccffcd770b 100644 --- a/drivers/acpi/acpica/nsdump.c +++ b/drivers/acpi/acpica/nsdump.c @@ -170,6 +170,7 @@ acpi_ns_dump_one_object(acpi_handle obj_handle, } type = this_node->type; + info->count++; /* Check if the owner matches */ @@ -639,6 +640,7 @@ acpi_ns_dump_objects(acpi_object_type type, return; } + info.count = 0; info.debug_level = ACPI_LV_TABLES; info.owner_id = owner_id; info.display_type = display_type; @@ -649,6 +651,7 @@ acpi_ns_dump_objects(acpi_object_type type, acpi_ns_dump_one_object, NULL, (void *)&info, NULL); + acpi_os_printf("\nNamespace node count: %u\n\n", info.count); (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); } diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index 68422afc365f..bc5f05906bd1 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -515,6 +515,22 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } + if (walk_state->opcode == AML_SCOPE_OP) { + /* + * If the scope op fails to parse, skip the body of the + * scope op because the parse failure indicates that the + * device may not exist. + */ + walk_state->parser_state.aml = + walk_state->aml + 1; + walk_state->parser_state.aml = + acpi_ps_get_next_package_end + (&walk_state->parser_state); + walk_state->aml = + walk_state->parser_state.aml; + ACPI_ERROR((AE_INFO, + "Skipping Scope block")); + } continue; } @@ -557,7 +573,40 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } - + if ((walk_state->control_state) && + ((walk_state->control_state->control. + opcode == AML_IF_OP) + || (walk_state->control_state->control. + opcode == AML_WHILE_OP))) { + /* + * If the if/while op fails to parse, we will skip parsing + * the body of the op. + */ + parser_state->aml = + walk_state->control_state->control. + aml_predicate_start + 1; + parser_state->aml = + acpi_ps_get_next_package_end + (parser_state); + walk_state->aml = parser_state->aml; + + ACPI_ERROR((AE_INFO, + "Skipping While/If block")); + if (*walk_state->aml == AML_ELSE_OP) { + ACPI_ERROR((AE_INFO, + "Skipping Else block")); + walk_state->parser_state.aml = + walk_state->aml + 1; + walk_state->parser_state.aml = + acpi_ps_get_next_package_end + (parser_state); + walk_state->aml = + parser_state->aml; + } + ACPI_FREE(acpi_ut_pop_generic_state + (&walk_state->control_state)); + } + op = NULL; continue; } } diff --git a/drivers/acpi/acpica/psobject.c b/drivers/acpi/acpica/psobject.c index 7d9d0151ee54..3138e7a00da8 100644 --- a/drivers/acpi/acpica/psobject.c +++ b/drivers/acpi/acpica/psobject.c @@ -12,6 +12,7 @@ #include "acparser.h" #include "amlcode.h" #include "acconvert.h" +#include "acnamesp.h" #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME("psobject") @@ -549,6 +550,21 @@ acpi_ps_complete_op(struct acpi_walk_state *walk_state, do { if (*op) { + /* + * These Opcodes need to be removed from the namespace because they + * get created even if these opcodes cannot be created due to + * errors. + */ + if (((*op)->common.aml_opcode == AML_REGION_OP) + || ((*op)->common.aml_opcode == + AML_DATA_REGION_OP)) { + acpi_ns_delete_children((*op)->common. + node); + acpi_ns_remove_node((*op)->common.node); + (*op)->common.node = NULL; + acpi_ps_delete_parse_tree(*op); + } + status2 = acpi_ps_complete_this_op(walk_state, *op); if (ACPI_FAILURE(status2)) { @@ -574,6 +590,20 @@ acpi_ps_complete_op(struct acpi_walk_state *walk_state, #endif walk_state->prev_op = NULL; walk_state->prev_arg_types = walk_state->arg_types; + + if (walk_state->parse_flags & ACPI_PARSE_MODULE_LEVEL) { + /* + * There was something that went wrong while executing code at the + * module-level. We need to skip parsing whatever caused the + * error and keep going. One runtime error during the table load + * should not cause the entire table to not be loaded. This is + * because there could be correct AML beyond the parts that caused + * the runtime error. + */ + ACPI_ERROR((AE_INFO, + "Ignore error and continue table load")); + return_ACPI_STATUS(AE_OK); + } return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/pswalk.c b/drivers/acpi/acpica/pswalk.c index e0a442b8648b..bd6af8c87d48 100644 --- a/drivers/acpi/acpica/pswalk.c +++ b/drivers/acpi/acpica/pswalk.c @@ -25,22 +25,48 @@ ACPI_MODULE_NAME("pswalk") * DESCRIPTION: Delete a portion of or an entire parse tree. * ******************************************************************************/ +#include "amlcode.h" void acpi_ps_delete_parse_tree(union acpi_parse_object *subtree_root) { union acpi_parse_object *op = subtree_root; union acpi_parse_object *next = NULL; union acpi_parse_object *parent = NULL; + u32 level = 0; ACPI_FUNCTION_TRACE_PTR(ps_delete_parse_tree, subtree_root); + ACPI_DEBUG_PRINT((ACPI_DB_PARSE_TREES, " root %p\n", subtree_root)); + /* Visit all nodes in the subtree */ while (op) { - - /* Check if we are not ascending */ - if (op != parent) { + /* This is the descending case */ + + if (ACPI_IS_DEBUG_ENABLED + (ACPI_LV_PARSE_TREES, _COMPONENT)) { + + /* This debug option will print the entire parse tree */ + + acpi_os_printf(" %*.s%s %p", (level * 4), + " ", + acpi_ps_get_opcode_name(op-> + common. + aml_opcode), + op); + + if (op->named.aml_opcode == AML_INT_NAMEPATH_OP) { + acpi_os_printf(" %4.4s", + op->common.value.string); + } + if (op->named.aml_opcode == AML_STRING_OP) { + acpi_os_printf(" %s", + op->common.value.string); + } + acpi_os_printf("\n"); + } + /* Look for an argument or child of the current op */ next = acpi_ps_get_arg(op, 0); @@ -49,6 +75,7 @@ void acpi_ps_delete_parse_tree(union acpi_parse_object *subtree_root) /* Still going downward in tree (Op is not completed yet) */ op = next; + level++; continue; } } @@ -69,6 +96,7 @@ void acpi_ps_delete_parse_tree(union acpi_parse_object *subtree_root) if (next) { op = next; } else { + level--; op = parent; } } diff --git a/drivers/acpi/acpica/uterror.c b/drivers/acpi/acpica/uterror.c index 12d4a0f6b8d2..5a64ddaed8a3 100644 --- a/drivers/acpi/acpica/uterror.c +++ b/drivers/acpi/acpica/uterror.c @@ -182,20 +182,20 @@ acpi_ut_prefixed_namespace_error(const char *module_name, switch (lookup_status) { case AE_ALREADY_EXISTS: - acpi_os_printf(ACPI_MSG_BIOS_ERROR); + acpi_os_printf("\n" ACPI_MSG_BIOS_ERROR); message = "Failure creating"; break; case AE_NOT_FOUND: - acpi_os_printf(ACPI_MSG_BIOS_ERROR); - message = "Failure looking up"; + acpi_os_printf("\n" ACPI_MSG_BIOS_ERROR); + message = "Could not resolve"; break; default: - acpi_os_printf(ACPI_MSG_ERROR); - message = "Failure looking up"; + acpi_os_printf("\n" ACPI_MSG_ERROR); + message = "Failure resolving"; break; } diff --git a/drivers/acpi/acpica/utosi.c b/drivers/acpi/acpica/utosi.c index 1b415fa90cf8..64b63c81994b 100644 --- a/drivers/acpi/acpica/utosi.c +++ b/drivers/acpi/acpica/utosi.c @@ -69,6 +69,7 @@ static struct acpi_interface_info acpi_default_supported_interfaces[] = { {"Windows 2015", NULL, 0, ACPI_OSI_WIN_10}, /* Windows 10 - Added 03/2015 */ {"Windows 2016", NULL, 0, ACPI_OSI_WIN_10_RS1}, /* Windows 10 version 1607 - Added 12/2017 */ {"Windows 2017", NULL, 0, ACPI_OSI_WIN_10_RS2}, /* Windows 10 version 1703 - Added 12/2017 */ + {"Windows 2017.2", NULL, 0, ACPI_OSI_WIN_10_RS3}, /* Windows 10 version 1709 - Added 02/2018 */ /* Feature Group Strings */ diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index 9bff853e85f3..3c5ea7cb693e 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -524,7 +524,8 @@ retry: pr_warn(FW_WARN "too many record IDs!\n"); return 0; } - new_entries = kvmalloc(new_size * sizeof(entries[0]), GFP_KERNEL); + new_entries = kvmalloc_array(new_size, sizeof(entries[0]), + GFP_KERNEL); if (!new_entries) return -ENOMEM; memcpy(new_entries, entries, diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c index 9cb74115a43d..b1e9f81ebeea 100644 --- a/drivers/acpi/apei/hest.c +++ b/drivers/acpi/apei/hest.c @@ -195,7 +195,8 @@ static int __init hest_ghes_dev_register(unsigned int ghes_count) struct ghes_arr ghes_arr; ghes_arr.count = 0; - ghes_arr.ghes_devs = kmalloc(sizeof(void *) * ghes_count, GFP_KERNEL); + ghes_arr.ghes_devs = kmalloc_array(ghes_count, sizeof(void *), + GFP_KERNEL); if (!ghes_arr.ghes_devs) return -ENOMEM; diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index 3563103590c6..fe0183d48dcd 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c @@ -298,8 +298,8 @@ static int acpi_fan_get_fps(struct acpi_device *device) } fan->fps_count = obj->package.count - 1; /* minus revision field */ - fan->fps = devm_kzalloc(&device->dev, - fan->fps_count * sizeof(struct acpi_fan_fps), + fan->fps = devm_kcalloc(&device->dev, + fan->fps_count, sizeof(struct acpi_fan_fps), GFP_KERNEL); if (!fan->fps) { dev_err(&device->dev, "Not enough memory\n"); diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index b87252bf4571..d15814e1727f 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -1082,9 +1082,10 @@ static int __nfit_mem_init(struct acpi_nfit_desc *acpi_desc, continue; nfit_mem->nfit_flush = nfit_flush; flush = nfit_flush->flush; - nfit_mem->flush_wpq = devm_kzalloc(acpi_desc->dev, - flush->hint_count - * sizeof(struct resource), GFP_KERNEL); + nfit_mem->flush_wpq = devm_kcalloc(acpi_desc->dev, + flush->hint_count, + sizeof(struct resource), + GFP_KERNEL); if (!nfit_mem->flush_wpq) return -ENOMEM; for (i = 0; i < flush->hint_count; i++) { diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index a651ab3490d8..a303fd0e108c 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -343,8 +343,9 @@ static int acpi_processor_get_performance_states(struct acpi_processor *pr) pr->performance->state_count = pss->package.count; pr->performance->states = - kmalloc(sizeof(struct acpi_processor_px) * pss->package.count, - GFP_KERNEL); + kmalloc_array(pss->package.count, + sizeof(struct acpi_processor_px), + GFP_KERNEL); if (!pr->performance->states) { result = -ENOMEM; goto end; diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index 7f9aff4b8d62..fbc936cf2025 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -534,8 +534,9 @@ static int acpi_processor_get_throttling_states(struct acpi_processor *pr) pr->throttling.state_count = tss->package.count; pr->throttling.states_tss = - kmalloc(sizeof(struct acpi_processor_tx_tss) * tss->package.count, - GFP_KERNEL); + kmalloc_array(tss->package.count, + sizeof(struct acpi_processor_tx_tss), + GFP_KERNEL); if (!pr->throttling.states_tss) { result = -ENOMEM; goto end; diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index 4fc59c3bc673..41324f0b1bee 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -857,12 +857,12 @@ void acpi_irq_stats_init(void) num_gpes = acpi_current_gpe_count; num_counters = num_gpes + ACPI_NUM_FIXED_EVENTS + NUM_COUNTERS_EXTRA; - all_attrs = kzalloc(sizeof(struct attribute *) * (num_counters + 1), + all_attrs = kcalloc(num_counters + 1, sizeof(struct attribute *), GFP_KERNEL); if (all_attrs == NULL) return; - all_counters = kzalloc(sizeof(struct event_counter) * (num_counters), + all_counters = kcalloc(num_counters, sizeof(struct event_counter), GFP_KERNEL); if (all_counters == NULL) goto fail; @@ -871,7 +871,7 @@ void acpi_irq_stats_init(void) if (ACPI_FAILURE(status)) goto fail; - counter_attrs = kzalloc(sizeof(struct kobj_attribute) * (num_counters), + counter_attrs = kcalloc(num_counters, sizeof(struct kobj_attribute), GFP_KERNEL); if (counter_attrs == NULL) goto fail; diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index 4f382d51def1..2628806c64a2 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -692,8 +692,8 @@ int binder_alloc_mmap_handler(struct binder_alloc *alloc, } } #endif - alloc->pages = kzalloc(sizeof(alloc->pages[0]) * - ((vma->vm_end - vma->vm_start) / PAGE_SIZE), + alloc->pages = kcalloc((vma->vm_end - vma->vm_start) / PAGE_SIZE, + sizeof(alloc->pages[0]), GFP_KERNEL); if (alloc->pages == NULL) { ret = -ENOMEM; diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index c41b9eeabe7c..27d15ed7fa3d 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6987,7 +6987,7 @@ static void __init ata_parse_force_param(void) if (*p == ',') size++; - ata_force_tbl = kzalloc(sizeof(ata_force_tbl[0]) * size, GFP_KERNEL); + ata_force_tbl = kcalloc(size, sizeof(ata_force_tbl[0]), GFP_KERNEL); if (!ata_force_tbl) { printk(KERN_WARNING "ata: failed to extend force table, " "libata.force ignored\n"); diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c index 85aa76116a30..2ae1799f4992 100644 --- a/drivers/ata/libata-pmp.c +++ b/drivers/ata/libata-pmp.c @@ -340,7 +340,7 @@ static int sata_pmp_init_links (struct ata_port *ap, int nr_ports) int i, err; if (!pmp_link) { - pmp_link = kzalloc(sizeof(pmp_link[0]) * SATA_PMP_MAX_PORTS, + pmp_link = kcalloc(SATA_PMP_MAX_PORTS, sizeof(pmp_link[0]), GFP_NOIO); if (!pmp_link) return -ENOMEM; diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index cddf96f6e431..73ba8e134ca9 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -4114,13 +4114,13 @@ static int mv_platform_probe(struct platform_device *pdev) if (!host || !hpriv) return -ENOMEM; - hpriv->port_clks = devm_kzalloc(&pdev->dev, - sizeof(struct clk *) * n_ports, + hpriv->port_clks = devm_kcalloc(&pdev->dev, + n_ports, sizeof(struct clk *), GFP_KERNEL); if (!hpriv->port_clks) return -ENOMEM; - hpriv->port_phys = devm_kzalloc(&pdev->dev, - sizeof(struct phy *) * n_ports, + hpriv->port_phys = devm_kcalloc(&pdev->dev, + n_ports, sizeof(struct phy *), GFP_KERNEL); if (!hpriv->port_phys) return -ENOMEM; diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index 6ebc4e4820fc..99a38115b0a8 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -2094,7 +2094,8 @@ static int fore200e_alloc_rx_buf(struct fore200e *fore200e) DPRINTK(2, "rx buffers %d / %d are being allocated\n", scheme, magn); /* allocate the array of receive buffers */ - buffer = bsq->buffer = kzalloc(nbr * sizeof(struct buffer), GFP_KERNEL); + buffer = bsq->buffer = kcalloc(nbr, sizeof(struct buffer), + GFP_KERNEL); if (buffer == NULL) return -ENOMEM; diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c index be076606d30e..ff81a576347e 100644 --- a/drivers/atm/iphase.c +++ b/drivers/atm/iphase.c @@ -1618,7 +1618,7 @@ static int rx_init(struct atm_dev *dev) skb_queue_head_init(&iadev->rx_dma_q); iadev->rx_free_desc_qhead = NULL; - iadev->rx_open = kzalloc(4 * iadev->num_vc, GFP_KERNEL); + iadev->rx_open = kcalloc(4, iadev->num_vc, GFP_KERNEL); if (!iadev->rx_open) { printk(KERN_ERR DEV_LABEL "itf %d couldn't get free page\n", dev->number); diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c index 0df1a1c80b00..17283018269f 100644 --- a/drivers/atm/solos-pci.c +++ b/drivers/atm/solos-pci.c @@ -1291,7 +1291,8 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id) card->using_dma = 1; if (1) { /* All known FPGA versions so far */ card->dma_alignment = 3; - card->dma_bounce = kmalloc(card->nr_ports * BUF_SIZE, GFP_KERNEL); + card->dma_bounce = kmalloc_array(card->nr_ports, + BUF_SIZE, GFP_KERNEL); if (!card->dma_bounce) { dev_warn(&card->dev->dev, "Failed to allocate DMA bounce buffers\n"); err = -ENOMEM; diff --git a/drivers/auxdisplay/cfag12864b.c b/drivers/auxdisplay/cfag12864b.c index 6bd2f65e116a..7eebae7e322c 100644 --- a/drivers/auxdisplay/cfag12864b.c +++ b/drivers/auxdisplay/cfag12864b.c @@ -333,8 +333,8 @@ static int __init cfag12864b_init(void) goto none; } - cfag12864b_cache = kmalloc(sizeof(unsigned char) * - CFAG12864B_SIZE, GFP_KERNEL); + cfag12864b_cache = kmalloc(CFAG12864B_SIZE, + GFP_KERNEL); if (cfag12864b_cache == NULL) { printk(KERN_ERR CFAG12864B_NAME ": ERROR: " "can't alloc cache buffer (%i bytes)\n", diff --git a/drivers/base/dd.c b/drivers/base/dd.c index fb4e2df68d95..1435d7281c66 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -580,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_resume_suppliers(dev); + pm_runtime_get_suppliers(dev); if (dev->parent) pm_runtime_get_sync(dev->parent); @@ -591,6 +591,7 @@ 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/firmware_loader/fallback.c b/drivers/base/firmware_loader/fallback.c index b676a99c469c..7f732744f0d3 100644 --- a/drivers/base/firmware_loader/fallback.c +++ b/drivers/base/firmware_loader/fallback.c @@ -403,7 +403,7 @@ static int fw_realloc_pages(struct fw_sysfs *fw_sysfs, int min_size) fw_priv->page_array_size * 2); struct page **new_pages; - new_pages = vmalloc(new_array_size * sizeof(void *)); + new_pages = vmalloc(array_size(new_array_size, sizeof(void *))); if (!new_pages) { fw_load_abort(fw_sysfs); return -ENOMEM; diff --git a/drivers/base/power/common.c b/drivers/base/power/common.c index 7ae62b6355b8..df41b4780b3b 100644 --- a/drivers/base/power/common.c +++ b/drivers/base/power/common.c @@ -117,13 +117,50 @@ int dev_pm_domain_attach(struct device *dev, bool power_on) EXPORT_SYMBOL_GPL(dev_pm_domain_attach); /** + * dev_pm_domain_attach_by_id - Associate a device with one of its PM domains. + * @dev: The device used to lookup the PM domain. + * @index: The index of the PM domain. + * + * As @dev may only be attached to a single PM domain, the backend PM domain + * provider creates a virtual device to attach instead. If attachment succeeds, + * the ->detach() callback in the struct dev_pm_domain are assigned by the + * corresponding backend attach function, as to deal with detaching of the + * created virtual device. + * + * This function should typically be invoked by a driver during the probe phase, + * in case its device requires power management through multiple PM domains. The + * driver may benefit from using the received device, to configure device-links + * towards its original device. Depending on the use-case and if needed, the + * links may be dynamically changed by the driver, which allows it to control + * the power to the PM domains independently from each other. + * + * Callers must ensure proper synchronization of this function with power + * management callbacks. + * + * Returns the virtual created device when successfully attached to its PM + * domain, NULL in case @dev don't need a PM domain, else an ERR_PTR(). + * Note that, to detach the returned virtual device, the driver shall call + * dev_pm_domain_detach() on it, typically during the remove phase. + */ +struct device *dev_pm_domain_attach_by_id(struct device *dev, + unsigned int index) +{ + if (dev->pm_domain) + return ERR_PTR(-EEXIST); + + return genpd_dev_pm_attach_by_id(dev, index); +} +EXPORT_SYMBOL_GPL(dev_pm_domain_attach_by_id); + +/** * dev_pm_domain_detach - Detach a device from its PM domain. * @dev: Device to detach. * @power_off: Used to indicate whether we should power off the device. * - * This functions will reverse the actions from dev_pm_domain_attach() and thus - * try to detach the @dev from its PM domain. Typically it should be invoked - * from subsystem level code during the remove phase. + * This functions will reverse the actions from dev_pm_domain_attach() and + * dev_pm_domain_attach_by_id(), thus it detaches @dev from its PM domain. + * Typically it should be invoked during the remove phase, either from + * subsystem level code or from drivers. * * Callers must ensure proper synchronization of this function with power * management callbacks. diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 6f403d6fccb2..4925af5c4cf0 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -2171,6 +2171,15 @@ struct generic_pm_domain *of_genpd_remove_last(struct device_node *np) } EXPORT_SYMBOL_GPL(of_genpd_remove_last); +static void genpd_release_dev(struct device *dev) +{ + kfree(dev); +} + +static struct bus_type genpd_bus_type = { + .name = "genpd", +}; + /** * genpd_dev_pm_detach - Detach a device from its PM domain. * @dev: Device to detach. @@ -2208,6 +2217,10 @@ static void genpd_dev_pm_detach(struct device *dev, bool power_off) /* Check if PM domain can be powered off after removing this device. */ genpd_queue_power_off_work(pd); + + /* Unregister the device if it was created by genpd. */ + if (dev->bus == &genpd_bus_type) + device_unregister(dev); } static void genpd_dev_pm_sync(struct device *dev) @@ -2221,32 +2234,17 @@ static void genpd_dev_pm_sync(struct device *dev) genpd_queue_power_off_work(pd); } -/** - * genpd_dev_pm_attach - Attach a device to its PM domain using DT. - * @dev: Device to attach. - * - * Parse device's OF node to find a PM domain specifier. If such is found, - * attaches the device to retrieved pm_domain ops. - * - * 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) +static int __genpd_dev_pm_attach(struct device *dev, struct device_node *np, + unsigned int index) { struct of_phandle_args pd_args; struct generic_pm_domain *pd; int ret; - if (!dev->of_node) - return 0; - - ret = of_parse_phandle_with_args(dev->of_node, "power-domains", - "#power-domain-cells", 0, &pd_args); + ret = of_parse_phandle_with_args(np, "power-domains", + "#power-domain-cells", index, &pd_args); if (ret < 0) - return 0; + return ret; mutex_lock(&gpd_list_lock); pd = genpd_get_from_provider(&pd_args); @@ -2282,8 +2280,98 @@ int genpd_dev_pm_attach(struct device *dev) return ret ? -EPROBE_DEFER : 1; } + +/** + * genpd_dev_pm_attach - Attach a device to its PM domain using DT. + * @dev: Device to attach. + * + * Parse device's OF node to find a PM domain specifier. If such is found, + * attaches the device to retrieved pm_domain ops. + * + * Returns 1 on successfully attached PM domain, 0 when the device don't need a + * PM domain or when multiple power-domains exists for it, else a 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. + */ +int genpd_dev_pm_attach(struct device *dev) +{ + if (!dev->of_node) + return 0; + + /* + * Devices with multiple PM domains must be attached separately, as we + * can only attach one PM domain per device. + */ + if (of_count_phandle_with_args(dev->of_node, "power-domains", + "#power-domain-cells") != 1) + return 0; + + return __genpd_dev_pm_attach(dev, dev->of_node, 0); +} EXPORT_SYMBOL_GPL(genpd_dev_pm_attach); +/** + * genpd_dev_pm_attach_by_id - Associate a device with one of its PM domains. + * @dev: The device used to lookup the PM domain. + * @index: The index of the PM domain. + * + * Parse device's OF node to find a PM domain specifier at the provided @index. + * If such is found, creates a virtual device and attaches it to the retrieved + * pm_domain ops. To deal with detaching of the virtual device, the ->detach() + * callback in the struct dev_pm_domain are assigned to genpd_dev_pm_detach(). + * + * Returns the created virtual device if successfully attached PM domain, NULL + * when the device don't need a PM domain, else an ERR_PTR() in case of + * failures. If a power-domain exists for the device, but cannot be found or + * turned on, then ERR_PTR(-EPROBE_DEFER) is returned to ensure that the device + * is not probed and to re-try again later. + */ +struct device *genpd_dev_pm_attach_by_id(struct device *dev, + unsigned int index) +{ + struct device *genpd_dev; + int num_domains; + int ret; + + if (!dev->of_node) + return NULL; + + /* Deal only with devices using multiple PM domains. */ + num_domains = of_count_phandle_with_args(dev->of_node, "power-domains", + "#power-domain-cells"); + if (num_domains < 2 || index >= num_domains) + return NULL; + + /* Allocate and register device on the genpd bus. */ + genpd_dev = kzalloc(sizeof(*genpd_dev), GFP_KERNEL); + if (!genpd_dev) + return ERR_PTR(-ENOMEM); + + dev_set_name(genpd_dev, "genpd:%u:%s", index, dev_name(dev)); + genpd_dev->bus = &genpd_bus_type; + genpd_dev->release = genpd_release_dev; + + ret = device_register(genpd_dev); + if (ret) { + kfree(genpd_dev); + return ERR_PTR(ret); + } + + /* Try to attach the device to the PM domain at the specified index. */ + ret = __genpd_dev_pm_attach(genpd_dev, dev->of_node, index); + if (ret < 1) { + device_unregister(genpd_dev); + return ret ? ERR_PTR(ret) : NULL; + } + + pm_runtime_set_active(genpd_dev); + pm_runtime_enable(genpd_dev); + + return genpd_dev; +} +EXPORT_SYMBOL_GPL(genpd_dev_pm_attach_by_id); + static const struct of_device_id idle_state_match[] = { { .compatible = "domain-idle-state", }, { } @@ -2443,6 +2531,12 @@ unlock: } EXPORT_SYMBOL_GPL(of_genpd_opp_to_performance_state); +static int __init genpd_bus_init(void) +{ + return bus_register(&genpd_bus_type); +} +core_initcall(genpd_bus_init); + #endif /* CONFIG_PM_GENERIC_DOMAINS_OF */ diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index c6030f100c08..beb85c31f3fa 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -1563,16 +1563,37 @@ void pm_runtime_clean_up_links(struct device *dev) } /** - * pm_runtime_resume_suppliers - Resume supplier devices. + * pm_runtime_get_suppliers - Resume and reference-count supplier devices. * @dev: Consumer device. */ -void pm_runtime_resume_suppliers(struct device *dev) +void pm_runtime_get_suppliers(struct device *dev) { + struct device_link *link; int idx; idx = device_links_read_lock(); - rpm_get_suppliers(dev); + 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); device_links_read_unlock(idx); } diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c index 0f651efc58a1..d713738ce796 100644 --- a/drivers/base/power/sysfs.c +++ b/drivers/base/power/sysfs.c @@ -353,7 +353,7 @@ static ssize_t wakeup_count_show(struct device *dev, spin_lock_irq(&dev->power.lock); if (dev->power.wakeup) { - count = dev->power.wakeup->event_count; + count = dev->power.wakeup->wakeup_count; enabled = true; } spin_unlock_irq(&dev->power.lock); diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index 6ca77d6047d6..f6518067aa7d 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -5719,8 +5719,8 @@ static bool DAC960_CheckStatusBuffer(DAC960_Controller_T *Controller, Controller->CombinedStatusBufferLength = NewStatusBufferLength; return true; } - NewStatusBuffer = kmalloc(2 * Controller->CombinedStatusBufferLength, - GFP_ATOMIC); + NewStatusBuffer = kmalloc_array(2, Controller->CombinedStatusBufferLength, + GFP_ATOMIC); if (NewStatusBuffer == NULL) { DAC960_Warning("Unable to expand Combined Status Buffer - Truncating\n", diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 7655d6133139..a80809bd3057 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -511,7 +511,8 @@ static void drbd_calc_cpu_mask(cpumask_var_t *cpu_mask) { unsigned int *resources_per_cpu, min_index = ~0; - resources_per_cpu = kzalloc(nr_cpu_ids * sizeof(*resources_per_cpu), GFP_KERNEL); + resources_per_cpu = kcalloc(nr_cpu_ids, sizeof(*resources_per_cpu), + GFP_KERNEL); if (resources_per_cpu) { struct drbd_resource *resource; unsigned int cpu, min = ~0; diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 21e6d1b3b393..d6b6f434fd4b 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -524,7 +524,8 @@ static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd, __rq_for_each_bio(bio, rq) segments += bio_segments(bio); - bvec = kmalloc(sizeof(struct bio_vec) * segments, GFP_NOIO); + bvec = kmalloc_array(segments, sizeof(struct bio_vec), + GFP_NOIO); if (!bvec) return -EIO; cmd->bvec = bvec; diff --git a/drivers/block/null_blk.c b/drivers/block/null_blk.c index 2bdadd7f1454..7948049f6c43 100644 --- a/drivers/block/null_blk.c +++ b/drivers/block/null_blk.c @@ -1575,12 +1575,12 @@ static int setup_commands(struct nullb_queue *nq) struct nullb_cmd *cmd; int i, tag_size; - nq->cmds = kzalloc(nq->queue_depth * sizeof(*cmd), GFP_KERNEL); + nq->cmds = kcalloc(nq->queue_depth, sizeof(*cmd), GFP_KERNEL); if (!nq->cmds) return -ENOMEM; tag_size = ALIGN(nq->queue_depth, BITS_PER_LONG) / BITS_PER_LONG; - nq->tag_map = kzalloc(tag_size * sizeof(unsigned long), GFP_KERNEL); + nq->tag_map = kcalloc(tag_size, sizeof(unsigned long), GFP_KERNEL); if (!nq->tag_map) { kfree(nq->cmds); return -ENOMEM; @@ -1598,8 +1598,9 @@ static int setup_commands(struct nullb_queue *nq) static int setup_queues(struct nullb *nullb) { - nullb->queues = kzalloc(nullb->dev->submit_queues * - sizeof(struct nullb_queue), GFP_KERNEL); + nullb->queues = kcalloc(nullb->dev->submit_queues, + sizeof(struct nullb_queue), + GFP_KERNEL); if (!nullb->queues) return -ENOMEM; diff --git a/drivers/block/ps3vram.c b/drivers/block/ps3vram.c index 8fa4533a1249..1e3d5de9d838 100644 --- a/drivers/block/ps3vram.c +++ b/drivers/block/ps3vram.c @@ -407,8 +407,9 @@ static int ps3vram_cache_init(struct ps3_system_bus_device *dev) priv->cache.page_count = CACHE_PAGE_COUNT; priv->cache.page_size = CACHE_PAGE_SIZE; - priv->cache.tags = kzalloc(sizeof(struct ps3vram_tag) * - CACHE_PAGE_COUNT, GFP_KERNEL); + priv->cache.tags = kcalloc(CACHE_PAGE_COUNT, + sizeof(struct ps3vram_tag), + GFP_KERNEL); if (!priv->cache.tags) return -ENOMEM; diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index af354047ac4b..fa0729c1e776 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -2339,6 +2339,7 @@ static bool is_zero_bvecs(struct bio_vec *bvecs, u32 bytes) static int rbd_obj_issue_copyup(struct rbd_obj_request *obj_req, u32 bytes) { unsigned int num_osd_ops = obj_req->osd_req->r_num_ops; + int ret; dout("%s obj_req %p bytes %u\n", __func__, obj_req, bytes); rbd_assert(obj_req->osd_req->r_ops[0].op == CEPH_OSD_OP_STAT); @@ -2353,6 +2354,11 @@ static int rbd_obj_issue_copyup(struct rbd_obj_request *obj_req, u32 bytes) if (!obj_req->osd_req) return -ENOMEM; + ret = osd_req_op_cls_init(obj_req->osd_req, 0, CEPH_OSD_OP_CALL, "rbd", + "copyup"); + if (ret) + return ret; + /* * Only send non-zero copyup data to save some I/O and network * bandwidth -- zero copyup data is equivalent to the object not @@ -2362,9 +2368,6 @@ static int rbd_obj_issue_copyup(struct rbd_obj_request *obj_req, u32 bytes) dout("%s obj_req %p detected zeroes\n", __func__, obj_req); bytes = 0; } - - osd_req_op_cls_init(obj_req->osd_req, 0, CEPH_OSD_OP_CALL, "rbd", - "copyup"); osd_req_op_cls_request_data_bvecs(obj_req->osd_req, 0, obj_req->copyup_bvecs, obj_req->copyup_bvec_count, @@ -3397,7 +3400,6 @@ static void cancel_tasks_sync(struct rbd_device *rbd_dev) { dout("%s rbd_dev %p\n", __func__, rbd_dev); - cancel_delayed_work_sync(&rbd_dev->watch_dwork); cancel_work_sync(&rbd_dev->acquired_lock_work); cancel_work_sync(&rbd_dev->released_lock_work); cancel_delayed_work_sync(&rbd_dev->lock_dwork); @@ -3415,6 +3417,7 @@ static void rbd_unregister_watch(struct rbd_device *rbd_dev) rbd_dev->watch_state = RBD_WATCH_STATE_UNREGISTERED; mutex_unlock(&rbd_dev->watch_mutex); + cancel_delayed_work_sync(&rbd_dev->watch_dwork); ceph_osdc_flush_notifies(&rbd_dev->rbd_client->client->osdc); } diff --git a/drivers/block/rsxx/core.c b/drivers/block/rsxx/core.c index 09537bee387f..b7d71914a32a 100644 --- a/drivers/block/rsxx/core.c +++ b/drivers/block/rsxx/core.c @@ -873,7 +873,8 @@ static int rsxx_pci_probe(struct pci_dev *dev, dev_info(CARD_TO_DEV(card), "Failed reading the number of DMA targets\n"); - card->ctrl = kzalloc(card->n_targets * sizeof(*card->ctrl), GFP_KERNEL); + card->ctrl = kcalloc(card->n_targets, sizeof(*card->ctrl), + GFP_KERNEL); if (!card->ctrl) { st = -ENOMEM; goto failed_dma_setup; diff --git a/drivers/block/rsxx/dma.c b/drivers/block/rsxx/dma.c index beaccf197a5a..8fbc1bf6db3d 100644 --- a/drivers/block/rsxx/dma.c +++ b/drivers/block/rsxx/dma.c @@ -1038,7 +1038,7 @@ int rsxx_eeh_save_issued_dmas(struct rsxx_cardinfo *card) struct rsxx_dma *dma; struct list_head *issued_dmas; - issued_dmas = kzalloc(sizeof(*issued_dmas) * card->n_targets, + issued_dmas = kcalloc(card->n_targets, sizeof(*issued_dmas), GFP_KERNEL); if (!issued_dmas) return -ENOMEM; diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c index 66412eededda..a4bc74e72c39 100644 --- a/drivers/block/xen-blkback/xenbus.c +++ b/drivers/block/xen-blkback/xenbus.c @@ -139,7 +139,8 @@ static int xen_blkif_alloc_rings(struct xen_blkif *blkif) { unsigned int r; - blkif->rings = kzalloc(blkif->nr_rings * sizeof(struct xen_blkif_ring), GFP_KERNEL); + blkif->rings = kcalloc(blkif->nr_rings, sizeof(struct xen_blkif_ring), + GFP_KERNEL); if (!blkif->rings) return -ENOMEM; diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index ae00a82f350b..b5cedccb5d7d 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -1906,7 +1906,9 @@ static int negotiate_mq(struct blkfront_info *info) if (!info->nr_rings) info->nr_rings = 1; - info->rinfo = kzalloc(sizeof(struct blkfront_ring_info) * info->nr_rings, GFP_KERNEL); + info->rinfo = kcalloc(info->nr_rings, + sizeof(struct blkfront_ring_info), + GFP_KERNEL); if (!info->rinfo) { xenbus_dev_fatal(info->xbdev, -ENOMEM, "allocating ring_info structure"); return -ENOMEM; @@ -2216,15 +2218,18 @@ static int blkfront_setup_indirect(struct blkfront_ring_info *rinfo) } for (i = 0; i < BLK_RING_SIZE(info); i++) { - rinfo->shadow[i].grants_used = kzalloc( - sizeof(rinfo->shadow[i].grants_used[0]) * grants, - GFP_NOIO); - rinfo->shadow[i].sg = kzalloc(sizeof(rinfo->shadow[i].sg[0]) * psegs, GFP_NOIO); - if (info->max_indirect_segments) - rinfo->shadow[i].indirect_grants = kzalloc( - sizeof(rinfo->shadow[i].indirect_grants[0]) * - INDIRECT_GREFS(grants), + rinfo->shadow[i].grants_used = + kcalloc(grants, + sizeof(rinfo->shadow[i].grants_used[0]), GFP_NOIO); + rinfo->shadow[i].sg = kcalloc(psegs, + sizeof(rinfo->shadow[i].sg[0]), + GFP_NOIO); + if (info->max_indirect_segments) + rinfo->shadow[i].indirect_grants = + kcalloc(INDIRECT_GREFS(grants), + sizeof(rinfo->shadow[i].indirect_grants[0]), + GFP_NOIO); if ((rinfo->shadow[i].grants_used == NULL) || (rinfo->shadow[i].sg == NULL) || (info->max_indirect_segments && diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c index 8f9130ab5887..d0c5bc4e0703 100644 --- a/drivers/block/z2ram.c +++ b/drivers/block/z2ram.c @@ -197,8 +197,9 @@ static int z2_open(struct block_device *bdev, fmode_t mode) vaddr = (unsigned long)z_remap_nocache_nonser(paddr, size); #endif z2ram_map = - kmalloc((size/Z2RAM_CHUNKSIZE)*sizeof(z2ram_map[0]), - GFP_KERNEL); + kmalloc_array(size / Z2RAM_CHUNKSIZE, + sizeof(z2ram_map[0]), + GFP_KERNEL); if ( z2ram_map == NULL ) { printk( KERN_ERR DEVICE_NAME diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index da51293e7c03..7436b2d27fa3 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -898,7 +898,7 @@ static bool zram_meta_alloc(struct zram *zram, u64 disksize) size_t num_pages; num_pages = disksize >> PAGE_SHIFT; - zram->table = vzalloc(num_pages * sizeof(*zram->table)); + zram->table = vzalloc(array_size(num_pages, sizeof(*zram->table))); if (!zram->table) return false; diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig index 6dc177bf4c42..d1c0b60e9326 100644 --- a/drivers/bus/Kconfig +++ b/drivers/bus/Kconfig @@ -33,7 +33,6 @@ config HISILICON_LPC bool "Support for ISA I/O space on HiSilicon Hip06/7" depends on ARM64 && (ARCH_HISI || COMPILE_TEST) select INDIRECT_PIO - select MFD_CORE if ACPI help Driver to enable I/O access to devices attached to the Low Pin Count bus on the HiSilicon Hip06/7 SoC. diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c index 443e4c3fd357..b8184a903583 100644 --- a/drivers/bus/arm-cci.c +++ b/drivers/bus/arm-cci.c @@ -371,8 +371,6 @@ asmlinkage void __naked cci_enable_port_for_self(void) [sizeof_struct_cpu_port] "i" (sizeof(struct cpu_port)), [sizeof_struct_ace_port] "i" (sizeof(struct cci_ace_port)), [offsetof_port_phys] "i" (offsetof(struct cci_ace_port, phys)) ); - - unreachable(); } /** diff --git a/drivers/bus/fsl-mc/fsl-mc-allocator.c b/drivers/bus/fsl-mc/fsl-mc-allocator.c index fb1442b08962..e906ecfe23dd 100644 --- a/drivers/bus/fsl-mc/fsl-mc-allocator.c +++ b/drivers/bus/fsl-mc/fsl-mc-allocator.c @@ -354,8 +354,8 @@ int fsl_mc_populate_irq_pool(struct fsl_mc_bus *mc_bus, if (error < 0) return error; - irq_resources = devm_kzalloc(&mc_bus_dev->dev, - sizeof(*irq_resources) * irq_count, + irq_resources = devm_kcalloc(&mc_bus_dev->dev, + irq_count, sizeof(*irq_resources), GFP_KERNEL); if (!irq_resources) { error = -ENOMEM; @@ -455,7 +455,7 @@ int __must_check fsl_mc_allocate_irqs(struct fsl_mc_device *mc_dev) return -ENOSPC; } - irqs = devm_kzalloc(&mc_dev->dev, irq_count * sizeof(irqs[0]), + irqs = devm_kcalloc(&mc_dev->dev, irq_count, sizeof(irqs[0]), GFP_KERNEL); if (!irqs) return -ENOMEM; diff --git a/drivers/bus/hisi_lpc.c b/drivers/bus/hisi_lpc.c index 2d4611e4c339..d5f85455fa62 100644 --- a/drivers/bus/hisi_lpc.c +++ b/drivers/bus/hisi_lpc.c @@ -11,12 +11,12 @@ #include <linux/delay.h> #include <linux/io.h> #include <linux/logic_pio.h> -#include <linux/mfd/core.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_platform.h> #include <linux/pci.h> +#include <linux/serial_8250.h> #include <linux/slab.h> #define DRV_NAME "hisi-lpc" @@ -341,15 +341,6 @@ static const struct logic_pio_host_ops hisi_lpc_ops = { }; #ifdef CONFIG_ACPI -#define MFD_CHILD_NAME_PREFIX DRV_NAME"-" -#define MFD_CHILD_NAME_LEN (ACPI_ID_LEN + sizeof(MFD_CHILD_NAME_PREFIX) - 1) - -struct hisi_lpc_mfd_cell { - struct mfd_cell_acpi_match acpi_match; - char name[MFD_CHILD_NAME_LEN]; - char pnpid[ACPI_ID_LEN]; -}; - static int hisi_lpc_acpi_xlat_io_res(struct acpi_device *adev, struct acpi_device *host, struct resource *res) @@ -368,7 +359,7 @@ static int hisi_lpc_acpi_xlat_io_res(struct acpi_device *adev, } /* - * hisi_lpc_acpi_set_io_res - set the resources for a child's MFD + * hisi_lpc_acpi_set_io_res - set the resources for a child * @child: the device node to be updated the I/O resource * @hostdev: the device node associated with host controller * @res: double pointer to be set to the address of translated resources @@ -452,78 +443,122 @@ static int hisi_lpc_acpi_set_io_res(struct device *child, return 0; } +static int hisi_lpc_acpi_remove_subdev(struct device *dev, void *unused) +{ + platform_device_unregister(to_platform_device(dev)); + return 0; +} + +struct hisi_lpc_acpi_cell { + const char *hid; + const char *name; + void *pdata; + size_t pdata_size; +}; + /* * hisi_lpc_acpi_probe - probe children for ACPI FW * @hostdev: LPC host device pointer * * Returns 0 when successful, and a negative value for failure. * - * Scan all child devices and create a per-device MFD with - * logical PIO translated IO resources. + * Create a platform device per child, fixing up the resources + * from bus addresses to Logical PIO addresses. + * */ static int hisi_lpc_acpi_probe(struct device *hostdev) { struct acpi_device *adev = ACPI_COMPANION(hostdev); - struct hisi_lpc_mfd_cell *hisi_lpc_mfd_cells; - struct mfd_cell *mfd_cells; struct acpi_device *child; - int size, ret, count = 0, cell_num = 0; - - list_for_each_entry(child, &adev->children, node) - cell_num++; - - /* allocate the mfd cell and companion ACPI info, one per child */ - size = sizeof(*mfd_cells) + sizeof(*hisi_lpc_mfd_cells); - mfd_cells = devm_kcalloc(hostdev, cell_num, size, GFP_KERNEL); - if (!mfd_cells) - return -ENOMEM; + int ret; - hisi_lpc_mfd_cells = (struct hisi_lpc_mfd_cell *)&mfd_cells[cell_num]; /* Only consider the children of the host */ list_for_each_entry(child, &adev->children, node) { - struct mfd_cell *mfd_cell = &mfd_cells[count]; - struct hisi_lpc_mfd_cell *hisi_lpc_mfd_cell = - &hisi_lpc_mfd_cells[count]; - struct mfd_cell_acpi_match *acpi_match = - &hisi_lpc_mfd_cell->acpi_match; - char *name = hisi_lpc_mfd_cell[count].name; - char *pnpid = hisi_lpc_mfd_cell[count].pnpid; - struct mfd_cell_acpi_match match = { - .pnpid = pnpid, + const char *hid = acpi_device_hid(child); + const struct hisi_lpc_acpi_cell *cell; + struct platform_device *pdev; + const struct resource *res; + bool found = false; + int num_res; + + ret = hisi_lpc_acpi_set_io_res(&child->dev, &adev->dev, &res, + &num_res); + if (ret) { + dev_warn(hostdev, "set resource fail (%d)\n", ret); + goto fail; + } + + cell = (struct hisi_lpc_acpi_cell []){ + /* ipmi */ + { + .hid = "IPI0001", + .name = "hisi-lpc-ipmi", + }, + /* 8250-compatible uart */ + { + .hid = "HISI1031", + .name = "serial8250", + .pdata = (struct plat_serial8250_port []) { + { + .iobase = res->start, + .uartclk = 1843200, + .iotype = UPIO_PORT, + .flags = UPF_BOOT_AUTOCONF, + }, + {} + }, + .pdata_size = 2 * + sizeof(struct plat_serial8250_port), + }, + {} }; - /* - * For any instances of this host controller (Hip06 and Hip07 - * are the only chipsets), we would not have multiple slaves - * with the same HID. And in any system we would have just one - * controller active. So don't worrry about MFD name clashes. - */ - snprintf(name, MFD_CHILD_NAME_LEN, MFD_CHILD_NAME_PREFIX"%s", - acpi_device_hid(child)); - snprintf(pnpid, ACPI_ID_LEN, "%s", acpi_device_hid(child)); - - memcpy(acpi_match, &match, sizeof(*acpi_match)); - mfd_cell->name = name; - mfd_cell->acpi_match = acpi_match; - - ret = hisi_lpc_acpi_set_io_res(&child->dev, &adev->dev, - &mfd_cell->resources, - &mfd_cell->num_resources); - if (ret) { - dev_warn(&child->dev, "set resource fail (%d)\n", ret); - return ret; + for (; cell && cell->name; cell++) { + if (!strcmp(cell->hid, hid)) { + found = true; + break; + } } - count++; - } - ret = mfd_add_devices(hostdev, PLATFORM_DEVID_NONE, - mfd_cells, cell_num, NULL, 0, NULL); - if (ret) { - dev_err(hostdev, "failed to add mfd cells (%d)\n", ret); - return ret; + if (!found) { + dev_warn(hostdev, + "could not find cell for child device (%s)\n", + hid); + ret = -ENODEV; + goto fail; + } + + pdev = platform_device_alloc(cell->name, PLATFORM_DEVID_AUTO); + if (!pdev) { + ret = -ENOMEM; + goto fail; + } + + pdev->dev.parent = hostdev; + ACPI_COMPANION_SET(&pdev->dev, child); + + ret = platform_device_add_resources(pdev, res, num_res); + if (ret) + goto fail; + + ret = platform_device_add_data(pdev, cell->pdata, + cell->pdata_size); + if (ret) + goto fail; + + ret = platform_device_add(pdev); + if (ret) + goto fail; + + acpi_device_set_enumerated(child); } return 0; + +fail: + device_for_each_child(hostdev, NULL, + hisi_lpc_acpi_remove_subdev); + return ret; } static const struct acpi_device_id hisi_lpc_acpi_match[] = { diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index 7cd2fd04b212..1cc29629d238 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -19,6 +19,7 @@ #include <linux/platform_device.h> #include <linux/pm_domain.h> #include <linux/pm_runtime.h> +#include <linux/reset.h> #include <linux/of_address.h> #include <linux/of_platform.h> #include <linux/slab.h> @@ -32,10 +33,18 @@ static const char * const reg_names[] = { "rev", "sysc", "syss", }; enum sysc_clocks { SYSC_FCK, SYSC_ICK, + SYSC_OPTFCK0, + SYSC_OPTFCK1, + SYSC_OPTFCK2, + SYSC_OPTFCK3, + SYSC_OPTFCK4, + SYSC_OPTFCK5, + SYSC_OPTFCK6, + SYSC_OPTFCK7, SYSC_MAX_CLOCKS, }; -static const char * const clock_names[] = { "fck", "ick", }; +static const char * const clock_names[SYSC_ICK + 1] = { "fck", "ick", }; #define SYSC_IDLEMODE_MASK 3 #define SYSC_CLOCKACTIVITY_MASK 3 @@ -48,6 +57,8 @@ static const char * const clock_names[] = { "fck", "ick", }; * @module_va: virtual address of the interconnect target module * @offsets: register offsets from module base * @clocks: clocks used by the interconnect target module + * @clock_roles: clock role names for the found clocks + * @nr_clocks: number of clocks used by the interconnect target module * @legacy_mode: configured for legacy mode if set * @cap: interconnect target module capabilities * @cfg: interconnect target module configuration @@ -61,7 +72,10 @@ struct sysc { u32 module_size; void __iomem *module_va; int offsets[SYSC_MAX_REGS]; - struct clk *clocks[SYSC_MAX_CLOCKS]; + struct clk **clocks; + const char **clock_roles; + int nr_clocks; + struct reset_control *rsts; const char *legacy_mode; const struct sysc_capabilities *cap; struct sysc_config cfg; @@ -88,6 +102,11 @@ static u32 sysc_read(struct sysc *ddata, int offset) return readl_relaxed(ddata->module_va + offset); } +static bool sysc_opt_clks_needed(struct sysc *ddata) +{ + return !!(ddata->cfg.quirks & SYSC_QUIRK_OPT_CLKS_NEEDED); +} + static u32 sysc_read_revision(struct sysc *ddata) { int offset = ddata->offsets[SYSC_REVISION]; @@ -98,21 +117,28 @@ static u32 sysc_read_revision(struct sysc *ddata) return sysc_read(ddata, offset); } -static int sysc_get_one_clock(struct sysc *ddata, - enum sysc_clocks index) +static int sysc_get_one_clock(struct sysc *ddata, const char *name) { - const char *name; - int error; + int error, i, index = -ENODEV; + + if (!strncmp(clock_names[SYSC_FCK], name, 3)) + index = SYSC_FCK; + else if (!strncmp(clock_names[SYSC_ICK], name, 3)) + index = SYSC_ICK; + + if (index < 0) { + for (i = SYSC_OPTFCK0; i < SYSC_MAX_CLOCKS; i++) { + if (!ddata->clocks[i]) { + index = i; + break; + } + } + } - switch (index) { - case SYSC_FCK: - break; - case SYSC_ICK: - break; - default: - return -EINVAL; + if (index < 0) { + dev_err(ddata->dev, "clock %s not added\n", name); + return index; } - name = clock_names[index]; ddata->clocks[index] = devm_clk_get(ddata->dev, name); if (IS_ERR(ddata->clocks[index])) { @@ -138,10 +164,50 @@ static int sysc_get_one_clock(struct sysc *ddata, static int sysc_get_clocks(struct sysc *ddata) { - int i, error; + struct device_node *np = ddata->dev->of_node; + struct property *prop; + const char *name; + int nr_fck = 0, nr_ick = 0, i, error = 0; - for (i = 0; i < SYSC_MAX_CLOCKS; i++) { - error = sysc_get_one_clock(ddata, i); + ddata->clock_roles = devm_kzalloc(ddata->dev, + sizeof(*ddata->clock_roles) * + SYSC_MAX_CLOCKS, + GFP_KERNEL); + if (!ddata->clock_roles) + return -ENOMEM; + + of_property_for_each_string(np, "clock-names", prop, name) { + if (!strncmp(clock_names[SYSC_FCK], name, 3)) + nr_fck++; + if (!strncmp(clock_names[SYSC_ICK], name, 3)) + nr_ick++; + ddata->clock_roles[ddata->nr_clocks] = name; + ddata->nr_clocks++; + } + + if (ddata->nr_clocks < 1) + return 0; + + if (ddata->nr_clocks > SYSC_MAX_CLOCKS) { + dev_err(ddata->dev, "too many clocks for %pOF\n", np); + + return -EINVAL; + } + + if (nr_fck > 1 || nr_ick > 1) { + dev_err(ddata->dev, "max one fck and ick for %pOF\n", np); + + return -EINVAL; + } + + ddata->clocks = devm_kzalloc(ddata->dev, + sizeof(*ddata->clocks) * ddata->nr_clocks, + GFP_KERNEL); + if (!ddata->clocks) + return -ENOMEM; + + for (i = 0; i < ddata->nr_clocks; i++) { + error = sysc_get_one_clock(ddata, ddata->clock_roles[i]); if (error && error != -ENOENT) return error; } @@ -150,6 +216,42 @@ static int sysc_get_clocks(struct sysc *ddata) } /** + * sysc_init_resets - reset module on init + * @ddata: device driver data + * + * A module can have both OCP softreset control and external rstctrl. + * If more complicated rstctrl resets are needed, please handle these + * directly from the child device driver and map only the module reset + * for the parent interconnect target module device. + * + * Automatic reset of the module on init can be skipped with the + * "ti,no-reset-on-init" device tree property. + */ +static int sysc_init_resets(struct sysc *ddata) +{ + int error; + + ddata->rsts = + devm_reset_control_array_get_optional_exclusive(ddata->dev); + if (IS_ERR(ddata->rsts)) + return PTR_ERR(ddata->rsts); + + if (ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT) + goto deassert; + + error = reset_control_assert(ddata->rsts); + if (error) + return error; + +deassert: + error = reset_control_deassert(ddata->rsts); + if (error) + return error; + + return 0; +} + +/** * sysc_parse_and_check_child_range - parses module IO region from ranges * @ddata: device driver data * @@ -533,9 +635,13 @@ static int __maybe_unused sysc_runtime_suspend(struct device *dev) goto idled; } - for (i = 0; i < SYSC_MAX_CLOCKS; i++) { + for (i = 0; i < ddata->nr_clocks; i++) { if (IS_ERR_OR_NULL(ddata->clocks[i])) continue; + + if (i >= SYSC_OPTFCK0 && !sysc_opt_clks_needed(ddata)) + break; + clk_disable(ddata->clocks[i]); } @@ -572,9 +678,13 @@ static int __maybe_unused sysc_runtime_resume(struct device *dev) goto awake; } - for (i = 0; i < SYSC_MAX_CLOCKS; i++) { + for (i = 0; i < ddata->nr_clocks; i++) { if (IS_ERR_OR_NULL(ddata->clocks[i])) continue; + + if (i >= SYSC_OPTFCK0 && !sysc_opt_clks_needed(ddata)) + break; + error = clk_enable(ddata->clocks[i]); if (error) return error; @@ -590,23 +700,103 @@ awake: static int sysc_suspend(struct device *dev) { struct sysc *ddata; + int error; ddata = dev_get_drvdata(dev); + if (ddata->cfg.quirks & (SYSC_QUIRK_RESOURCE_PROVIDER | + SYSC_QUIRK_LEGACY_IDLE)) + return 0; + if (!ddata->enabled) return 0; + dev_dbg(ddata->dev, "%s %s\n", __func__, + ddata->name ? ddata->name : ""); + + error = pm_runtime_put_sync_suspend(dev); + if (error < 0) { + dev_warn(ddata->dev, "%s not idle %i %s\n", + __func__, error, + ddata->name ? ddata->name : ""); + + return 0; + } + ddata->needs_resume = true; - return sysc_runtime_suspend(dev); + return 0; } static int sysc_resume(struct device *dev) { struct sysc *ddata; + int error; + + ddata = dev_get_drvdata(dev); + + if (ddata->cfg.quirks & (SYSC_QUIRK_RESOURCE_PROVIDER | + SYSC_QUIRK_LEGACY_IDLE)) + return 0; + + if (ddata->needs_resume) { + dev_dbg(ddata->dev, "%s %s\n", __func__, + ddata->name ? ddata->name : ""); + + error = pm_runtime_get_sync(dev); + if (error < 0) { + dev_err(ddata->dev, "%s error %i %s\n", + __func__, error, + ddata->name ? ddata->name : ""); + + return error; + } + + ddata->needs_resume = false; + } + + return 0; +} + +static int sysc_noirq_suspend(struct device *dev) +{ + struct sysc *ddata; ddata = dev_get_drvdata(dev); + + if (ddata->cfg.quirks & SYSC_QUIRK_LEGACY_IDLE) + return 0; + + if (!(ddata->cfg.quirks & SYSC_QUIRK_RESOURCE_PROVIDER)) + return 0; + + if (!ddata->enabled) + return 0; + + dev_dbg(ddata->dev, "%s %s\n", __func__, + ddata->name ? ddata->name : ""); + + ddata->needs_resume = true; + + return sysc_runtime_suspend(dev); +} + +static int sysc_noirq_resume(struct device *dev) +{ + struct sysc *ddata; + + ddata = dev_get_drvdata(dev); + + if (ddata->cfg.quirks & SYSC_QUIRK_LEGACY_IDLE) + return 0; + + if (!(ddata->cfg.quirks & SYSC_QUIRK_RESOURCE_PROVIDER)) + return 0; + if (ddata->needs_resume) { + dev_dbg(ddata->dev, "%s %s\n", __func__, + ddata->name ? ddata->name : ""); + ddata->needs_resume = false; return sysc_runtime_resume(dev); @@ -618,6 +808,7 @@ static int sysc_resume(struct device *dev) static const struct dev_pm_ops sysc_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(sysc_suspend, sysc_resume) + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(sysc_noirq_suspend, sysc_noirq_resume) SET_RUNTIME_PM_OPS(sysc_runtime_suspend, sysc_runtime_resume, NULL) @@ -649,9 +840,29 @@ struct sysc_revision_quirk { } static const struct sysc_revision_quirk sysc_revision_quirks[] = { + /* These need to use noirq_suspend */ + SYSC_QUIRK("control", 0, 0, 0x10, -1, 0x40000900, 0xffffffff, + SYSC_QUIRK_RESOURCE_PROVIDER), + SYSC_QUIRK("i2c", 0, 0, 0x10, 0x90, 0x5040000a, 0xffffffff, + SYSC_QUIRK_RESOURCE_PROVIDER), + SYSC_QUIRK("mcspi", 0, 0, 0x10, -1, 0x40300a0b, 0xffffffff, + SYSC_QUIRK_RESOURCE_PROVIDER), + SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x40000100, 0xffffffff, + SYSC_QUIRK_RESOURCE_PROVIDER), + SYSC_QUIRK("ocp2scp", 0, 0, 0x10, 0x14, 0x50060005, 0xffffffff, + SYSC_QUIRK_RESOURCE_PROVIDER), + SYSC_QUIRK("padconf", 0, 0, 0x10, -1, 0x4fff0800, 0xffffffff, + SYSC_QUIRK_RESOURCE_PROVIDER), + SYSC_QUIRK("scm", 0, 0, 0x10, -1, 0x40000900, 0xffffffff, + SYSC_QUIRK_RESOURCE_PROVIDER), + SYSC_QUIRK("scrm", 0, 0, -1, -1, 0x00000010, 0xffffffff, + SYSC_QUIRK_RESOURCE_PROVIDER), + SYSC_QUIRK("sdma", 0, 0, 0x2c, 0x28, 0x00010900, 0xffffffff, + SYSC_QUIRK_RESOURCE_PROVIDER), + /* These drivers need to be fixed to not use pm_runtime_irq_safe() */ SYSC_QUIRK("gpio", 0, 0, 0x10, 0x114, 0x50600801, 0xffffffff, - SYSC_QUIRK_LEGACY_IDLE), + SYSC_QUIRK_LEGACY_IDLE | SYSC_QUIRK_OPT_CLKS_IN_RESET), SYSC_QUIRK("mmu", 0, 0, 0x10, 0x14, 0x00000020, 0xffffffff, SYSC_QUIRK_LEGACY_IDLE), SYSC_QUIRK("mmu", 0, 0, 0x10, 0x14, 0x00000030, 0xffffffff, @@ -664,8 +875,40 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = { SYSC_QUIRK_LEGACY_IDLE), SYSC_QUIRK("timer", 0, 0, 0x10, 0x14, 0x00000015, 0xffffffff, SYSC_QUIRK_LEGACY_IDLE), + /* Some timers on omap4 and later */ + SYSC_QUIRK("timer", 0, 0, 0x10, -1, 0x4fff1301, 0xffffffff, + SYSC_QUIRK_LEGACY_IDLE), SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000052, 0xffffffff, SYSC_QUIRK_LEGACY_IDLE), + /* Uarts on omap4 and later */ + SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x50411e03, 0xffffffff, + SYSC_QUIRK_LEGACY_IDLE), + + /* These devices don't yet suspend properly without legacy setting */ + SYSC_QUIRK("sdio", 0, 0, 0x10, -1, 0x40202301, 0xffffffff, + SYSC_QUIRK_LEGACY_IDLE), + SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0500, 0xffffffff, + SYSC_QUIRK_LEGACY_IDLE), + SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0d00, 0xffffffff, + SYSC_QUIRK_LEGACY_IDLE), + +#ifdef DEBUG + SYSC_QUIRK("aess", 0, 0, 0x10, -1, 0x40000000, 0xffffffff, 0), + SYSC_QUIRK("gpu", 0, 0x1fc00, 0x1fc10, -1, 0, 0, 0), + SYSC_QUIRK("hdq1w", 0, 0, 0x14, 0x18, 0x00000006, 0xffffffff, 0), + SYSC_QUIRK("hsi", 0, 0, 0x10, 0x14, 0x50043101, 0xffffffff, 0), + SYSC_QUIRK("iss", 0, 0, 0x10, -1, 0x40000101, 0xffffffff, 0), + SYSC_QUIRK("mcasp", 0, 0, 0x4, -1, 0x44306302, 0xffffffff, 0), + SYSC_QUIRK("mcbsp", 0, -1, 0x8c, -1, 0, 0, 0), + SYSC_QUIRK("mailbox", 0, 0, 0x10, -1, 0x00000400, 0xffffffff, 0), + SYSC_QUIRK("slimbus", 0, 0, 0x10, -1, 0x40000902, 0xffffffff, 0), + SYSC_QUIRK("slimbus", 0, 0, 0x10, -1, 0x40002903, 0xffffffff, 0), + SYSC_QUIRK("spinlock", 0, 0, 0x10, -1, 0x50020000, 0xffffffff, 0), + SYSC_QUIRK("usbhstll", 0, 0, 0x10, 0x14, 0x00000004, 0xffffffff, 0), + SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, 0x14, 0x50700100, 0xffffffff, 0), + SYSC_QUIRK("usb_otg_hs", 0, 0x400, 0x404, 0x408, 0x00000050, + 0xffffffff, 0), +#endif }; static void sysc_init_revision_quirks(struct sysc *ddata) @@ -716,6 +959,7 @@ static int sysc_init_module(struct sysc *ddata) return 0; } + ddata->revision = sysc_read_revision(ddata); pm_runtime_put_sync(ddata->dev); @@ -811,29 +1055,58 @@ static int sysc_init_syss_mask(struct sysc *ddata) } /* - * Many child device drivers need to have fck available to get the clock - * rate for device internal configuration. + * Many child device drivers need to have fck and opt clocks available + * to get the clock rate for device internal configuration etc. */ -static int sysc_child_add_fck(struct sysc *ddata, - struct device *child) +static int sysc_child_add_named_clock(struct sysc *ddata, + struct device *child, + const char *name) { - struct clk *fck; + struct clk *clk; struct clk_lookup *l; - const char *name = clock_names[SYSC_FCK]; + int error = 0; - if (IS_ERR_OR_NULL(ddata->clocks[SYSC_FCK])) + if (!name) return 0; - fck = clk_get(child, name); - if (!IS_ERR(fck)) { - clk_put(fck); + clk = clk_get(child, name); + if (!IS_ERR(clk)) { + clk_put(clk); return -EEXIST; } - l = clkdev_create(ddata->clocks[SYSC_FCK], name, dev_name(child)); + clk = clk_get(ddata->dev, name); + if (IS_ERR(clk)) + return -ENODEV; + + l = clkdev_create(clk, name, dev_name(child)); + if (!l) + error = -ENOMEM; + + clk_put(clk); + + return error; +} + +static int sysc_child_add_clocks(struct sysc *ddata, + struct device *child) +{ + int i, error; + + for (i = 0; i < ddata->nr_clocks; i++) { + error = sysc_child_add_named_clock(ddata, + child, + ddata->clock_roles[i]); + if (error && error != -EEXIST) { + dev_err(ddata->dev, "could not add child clock %s: %i\n", + ddata->clock_roles[i], error); + + return error; + } + } - return l ? 0 : -ENODEV; + return 0; } static struct device_type sysc_device_type = { @@ -891,18 +1164,33 @@ static int sysc_child_suspend_noirq(struct device *dev) ddata = sysc_child_to_parent(dev); + dev_dbg(ddata->dev, "%s %s\n", __func__, + ddata->name ? ddata->name : ""); + error = pm_generic_suspend_noirq(dev); - if (error) + if (error) { + dev_err(dev, "%s error at %i: %i\n", + __func__, __LINE__, error); + return error; + } if (!pm_runtime_status_suspended(dev)) { error = pm_generic_runtime_suspend(dev); - if (error) + if (error) { + dev_err(dev, "%s error at %i: %i\n", + __func__, __LINE__, error); + return error; + } error = sysc_runtime_suspend(ddata->dev); - if (error) + if (error) { + dev_err(dev, "%s error at %i: %i\n", + __func__, __LINE__, error); + return error; + } ddata->child_needs_resume = true; } @@ -917,6 +1205,9 @@ static int sysc_child_resume_noirq(struct device *dev) ddata = sysc_child_to_parent(dev); + dev_dbg(ddata->dev, "%s %s\n", __func__, + ddata->name ? ddata->name : ""); + if (ddata->child_needs_resume) { ddata->child_needs_resume = false; @@ -983,10 +1274,9 @@ static int sysc_notifier_call(struct notifier_block *nb, switch (event) { case BUS_NOTIFY_ADD_DEVICE: - error = sysc_child_add_fck(ddata, dev); - if (error && error != -EEXIST) - dev_warn(ddata->dev, "could not add %s fck: %i\n", - dev_name(dev), error); + error = sysc_child_add_clocks(ddata, dev); + if (error) + return error; sysc_legacy_idle_quirk(ddata, dev); break; default: @@ -1314,6 +1604,11 @@ static void ti_sysc_idle(struct work_struct *work) pm_runtime_put_sync(ddata->dev); } +static const struct of_device_id sysc_match_table[] = { + { .compatible = "simple-bus", }, + { /* sentinel */ }, +}; + static int sysc_probe(struct platform_device *pdev) { struct ti_sysc_platform_data *pdata = dev_get_platdata(&pdev->dev); @@ -1359,8 +1654,11 @@ static int sysc_probe(struct platform_device *pdev) if (error) goto unprepare; - pm_runtime_enable(ddata->dev); + error = sysc_init_resets(ddata); + if (error) + return error; + pm_runtime_enable(ddata->dev); error = sysc_init_module(ddata); if (error) goto unprepare; @@ -1375,8 +1673,8 @@ static int sysc_probe(struct platform_device *pdev) sysc_show_registers(ddata); ddata->dev->type = &sysc_device_type; - error = of_platform_populate(ddata->dev->of_node, - NULL, pdata ? pdata->auxdata : NULL, + error = of_platform_populate(ddata->dev->of_node, sysc_match_table, + pdata ? pdata->auxdata : NULL, ddata->dev); if (error) goto err; @@ -1391,6 +1689,9 @@ static int sysc_probe(struct platform_device *pdev) pm_runtime_put(&pdev->dev); } + if (!of_get_available_child_count(ddata->dev->of_node)) + reset_control_assert(ddata->rsts); + return 0; err: @@ -1420,6 +1721,7 @@ static int sysc_remove(struct platform_device *pdev) pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); + reset_control_assert(ddata->rsts); unprepare: sysc_unprepare(ddata); diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 9adc8c3eb0fa..a78b8e7085e9 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -2132,7 +2132,7 @@ static int cdrom_read_cdda_old(struct cdrom_device_info *cdi, __u8 __user *ubuf, */ nr = nframes; do { - cgc.buffer = kmalloc(CD_FRAMESIZE_RAW * nr, GFP_KERNEL); + cgc.buffer = kmalloc_array(nr, CD_FRAMESIZE_RAW, GFP_KERNEL); if (cgc.buffer) break; diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c index b450544dcaf0..6914e4f0ce98 100644 --- a/drivers/char/agp/amd-k7-agp.c +++ b/drivers/char/agp/amd-k7-agp.c @@ -85,7 +85,8 @@ static int amd_create_gatt_pages(int nr_tables) int retval = 0; int i; - tables = kzalloc((nr_tables + 1) * sizeof(struct amd_page_map *),GFP_KERNEL); + tables = kcalloc(nr_tables + 1, sizeof(struct amd_page_map *), + GFP_KERNEL); if (tables == NULL) return -ENOMEM; diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c index 88b4cbee4dac..20bf5f78a362 100644 --- a/drivers/char/agp/ati-agp.c +++ b/drivers/char/agp/ati-agp.c @@ -108,7 +108,8 @@ static int ati_create_gatt_pages(int nr_tables) int retval = 0; int i; - tables = kzalloc((nr_tables + 1) * sizeof(struct ati_page_map *),GFP_KERNEL); + tables = kcalloc(nr_tables + 1, sizeof(struct ati_page_map *), + GFP_KERNEL); if (tables == NULL) return -ENOMEM; diff --git a/drivers/char/agp/compat_ioctl.c b/drivers/char/agp/compat_ioctl.c index 2053f70ef66b..52ffe1706ce0 100644 --- a/drivers/char/agp/compat_ioctl.c +++ b/drivers/char/agp/compat_ioctl.c @@ -98,11 +98,15 @@ static int compat_agpioc_reserve_wrap(struct agp_file_private *priv, void __user if (ureserve.seg_count >= 16384) return -EINVAL; - usegment = kmalloc(sizeof(*usegment) * ureserve.seg_count, GFP_KERNEL); + usegment = kmalloc_array(ureserve.seg_count, + sizeof(*usegment), + GFP_KERNEL); if (!usegment) return -ENOMEM; - ksegment = kmalloc(sizeof(*ksegment) * kreserve.seg_count, GFP_KERNEL); + ksegment = kmalloc_array(kreserve.seg_count, + sizeof(*ksegment), + GFP_KERNEL); if (!ksegment) { kfree(usegment); return -ENOMEM; diff --git a/drivers/char/agp/isoch.c b/drivers/char/agp/isoch.c index fc8e1bc3347d..31c374b1b91b 100644 --- a/drivers/char/agp/isoch.c +++ b/drivers/char/agp/isoch.c @@ -93,7 +93,8 @@ static int agp_3_5_isochronous_node_enable(struct agp_bridge_data *bridge, * We'll work with an array of isoch_data's (one for each * device in dev_list) throughout this function. */ - if ((master = kmalloc(ndevs * sizeof(*master), GFP_KERNEL)) == NULL) { + master = kmalloc_array(ndevs, sizeof(*master), GFP_KERNEL); + if (master == NULL) { ret = -ENOMEM; goto get_out; } diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c index 3051c73bc383..e7d5bdc02d93 100644 --- a/drivers/char/agp/sgi-agp.c +++ b/drivers/char/agp/sgi-agp.c @@ -280,9 +280,9 @@ static int agp_sgi_init(void) else return 0; - sgi_tioca_agp_bridges = kmalloc(tioca_gart_found * - sizeof(struct agp_bridge_data *), - GFP_KERNEL); + sgi_tioca_agp_bridges = kmalloc_array(tioca_gart_found, + sizeof(struct agp_bridge_data *), + GFP_KERNEL); if (!sgi_tioca_agp_bridges) return -ENOMEM; diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c index 4dbdd3bc9bb8..7729414100ff 100644 --- a/drivers/char/agp/sworks-agp.c +++ b/drivers/char/agp/sworks-agp.c @@ -96,7 +96,7 @@ static int serverworks_create_gatt_pages(int nr_tables) int retval = 0; int i; - tables = kzalloc((nr_tables + 1) * sizeof(struct serverworks_page_map *), + tables = kcalloc(nr_tables + 1, sizeof(struct serverworks_page_map *), GFP_KERNEL); if (tables == NULL) return -ENOMEM; diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c index 79d8c84693a1..31fcd0430426 100644 --- a/drivers/char/agp/uninorth-agp.c +++ b/drivers/char/agp/uninorth-agp.c @@ -402,7 +402,9 @@ static int uninorth_create_gatt_table(struct agp_bridge_data *bridge) if (table == NULL) return -ENOMEM; - uninorth_priv.pages_arr = kmalloc((1 << page_order) * sizeof(struct page*), GFP_KERNEL); + uninorth_priv.pages_arr = kmalloc_array(1 << page_order, + sizeof(struct page *), + GFP_KERNEL); if (uninorth_priv.pages_arr == NULL) goto enomem; diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c index 22f634eb09fd..18e4650c233b 100644 --- a/drivers/char/ipmi/ipmi_ssif.c +++ b/drivers/char/ipmi/ipmi_ssif.c @@ -1757,7 +1757,8 @@ static unsigned short *ssif_address_list(void) list_for_each_entry(info, &ssif_infos, link) count++; - address_list = kzalloc(sizeof(*address_list) * (count + 1), GFP_KERNEL); + address_list = kcalloc(count + 1, sizeof(*address_list), + GFP_KERNEL); if (!address_list) return NULL; diff --git a/drivers/char/raw.c b/drivers/char/raw.c index 293167c6e254..fd6eec8085b4 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -321,7 +321,8 @@ static int __init raw_init(void) max_raw_minors = MAX_RAW_MINORS; } - raw_devices = vzalloc(sizeof(struct raw_device_data) * max_raw_minors); + raw_devices = vzalloc(array_size(max_raw_minors, + sizeof(struct raw_device_data))); if (!raw_devices) { printk(KERN_ERR "Not enough memory for raw device structures\n"); ret = -ENOMEM; diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index 96c77c8e7f40..d31b09099216 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -980,7 +980,7 @@ static int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip) goto out; } - chip->cc_attrs_tbl = devm_kzalloc(&chip->dev, 4 * nr_commands, + chip->cc_attrs_tbl = devm_kcalloc(&chip->dev, 4, nr_commands, GFP_KERNEL); rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY); diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 21085515814f..17084cfcf53e 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -433,8 +433,7 @@ static struct port_buffer *alloc_buf(struct virtio_device *vdev, size_t buf_size * Allocate buffer and the sg list. The sg list array is allocated * directly after the port_buffer struct. */ - buf = kmalloc(sizeof(*buf) + sizeof(struct scatterlist) * pages, - GFP_KERNEL); + buf = kmalloc(struct_size(buf, sg, pages), GFP_KERNEL); if (!buf) goto fail; @@ -1892,13 +1891,14 @@ static int init_vqs(struct ports_device *portdev) nr_ports = portdev->max_nr_ports; nr_queues = use_multiport(portdev) ? (nr_ports + 1) * 2 : 2; - vqs = kmalloc(nr_queues * sizeof(struct virtqueue *), GFP_KERNEL); - io_callbacks = kmalloc(nr_queues * sizeof(vq_callback_t *), GFP_KERNEL); - io_names = kmalloc(nr_queues * sizeof(char *), GFP_KERNEL); - portdev->in_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *), - GFP_KERNEL); - portdev->out_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *), - GFP_KERNEL); + vqs = kmalloc_array(nr_queues, sizeof(struct virtqueue *), GFP_KERNEL); + io_callbacks = kmalloc_array(nr_queues, sizeof(vq_callback_t *), + GFP_KERNEL); + io_names = kmalloc_array(nr_queues, sizeof(char *), GFP_KERNEL); + portdev->in_vqs = kmalloc_array(nr_ports, sizeof(struct virtqueue *), + GFP_KERNEL); + portdev->out_vqs = kmalloc_array(nr_ports, sizeof(struct virtqueue *), + GFP_KERNEL); if (!vqs || !io_callbacks || !io_names || !portdev->in_vqs || !portdev->out_vqs) { err = -ENOMEM; diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c index 9e0b2f2b48e7..7bef0666ae7e 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c @@ -734,7 +734,7 @@ static void bcm2835_pll_debug_init(struct clk_hw *hw, const struct bcm2835_pll_data *data = pll->data; struct debugfs_reg32 *regs; - regs = devm_kzalloc(cprman->dev, 7 * sizeof(*regs), GFP_KERNEL); + regs = devm_kcalloc(cprman->dev, 7, sizeof(*regs), GFP_KERNEL); if (!regs) return; @@ -865,7 +865,7 @@ static void bcm2835_pll_divider_debug_init(struct clk_hw *hw, const struct bcm2835_pll_divider_data *data = divider->data; struct debugfs_reg32 *regs; - regs = devm_kzalloc(cprman->dev, 7 * sizeof(*regs), GFP_KERNEL); + regs = devm_kcalloc(cprman->dev, 7, sizeof(*regs), GFP_KERNEL); if (!regs) return; diff --git a/drivers/clk/renesas/clk-r8a7740.c b/drivers/clk/renesas/clk-r8a7740.c index d074f8e982d0..a7a30d2eca41 100644 --- a/drivers/clk/renesas/clk-r8a7740.c +++ b/drivers/clk/renesas/clk-r8a7740.c @@ -161,7 +161,7 @@ static void __init r8a7740_cpg_clocks_init(struct device_node *np) } cpg = kzalloc(sizeof(*cpg), GFP_KERNEL); - clks = kzalloc(num_clks * sizeof(*clks), GFP_KERNEL); + clks = kcalloc(num_clks, sizeof(*clks), GFP_KERNEL); if (cpg == NULL || clks == NULL) { /* We're leaking memory on purpose, there's no point in cleaning * up as the system won't boot anyway. diff --git a/drivers/clk/renesas/clk-r8a7779.c b/drivers/clk/renesas/clk-r8a7779.c index 27fbfafaf2cd..5adcca4656c3 100644 --- a/drivers/clk/renesas/clk-r8a7779.c +++ b/drivers/clk/renesas/clk-r8a7779.c @@ -138,7 +138,7 @@ static void __init r8a7779_cpg_clocks_init(struct device_node *np) } cpg = kzalloc(sizeof(*cpg), GFP_KERNEL); - clks = kzalloc(CPG_NUM_CLOCKS * sizeof(*clks), GFP_KERNEL); + clks = kcalloc(CPG_NUM_CLOCKS, sizeof(*clks), GFP_KERNEL); if (cpg == NULL || clks == NULL) { /* We're leaking memory on purpose, there's no point in cleaning * up as the system won't boot anyway. diff --git a/drivers/clk/renesas/clk-rcar-gen2.c b/drivers/clk/renesas/clk-rcar-gen2.c index ee32a022e6da..bccd62f2cb09 100644 --- a/drivers/clk/renesas/clk-rcar-gen2.c +++ b/drivers/clk/renesas/clk-rcar-gen2.c @@ -417,7 +417,7 @@ static void __init rcar_gen2_cpg_clocks_init(struct device_node *np) } cpg = kzalloc(sizeof(*cpg), GFP_KERNEL); - clks = kzalloc(num_clks * sizeof(*clks), GFP_KERNEL); + clks = kcalloc(num_clks, sizeof(*clks), GFP_KERNEL); if (cpg == NULL || clks == NULL) { /* We're leaking memory on purpose, there's no point in cleaning * up as the system won't boot anyway. diff --git a/drivers/clk/renesas/clk-rz.c b/drivers/clk/renesas/clk-rz.c index 67dd712aa723..ac2f86d626b6 100644 --- a/drivers/clk/renesas/clk-rz.c +++ b/drivers/clk/renesas/clk-rz.c @@ -97,7 +97,7 @@ static void __init rz_cpg_clocks_init(struct device_node *np) return; cpg = kzalloc(sizeof(*cpg), GFP_KERNEL); - clks = kzalloc(num_clks * sizeof(*clks), GFP_KERNEL); + clks = kcalloc(num_clks, sizeof(*clks), GFP_KERNEL); BUG_ON(!cpg || !clks); cpg->data.clks = clks; diff --git a/drivers/clk/st/clkgen-fsyn.c b/drivers/clk/st/clkgen-fsyn.c index 14819d919df1..a79d81985c4e 100644 --- a/drivers/clk/st/clkgen-fsyn.c +++ b/drivers/clk/st/clkgen-fsyn.c @@ -874,7 +874,7 @@ static void __init st_of_create_quadfs_fsynths( return; clk_data->clk_num = QUADFS_MAX_CHAN; - clk_data->clks = kzalloc(QUADFS_MAX_CHAN * sizeof(struct clk *), + clk_data->clks = kcalloc(QUADFS_MAX_CHAN, sizeof(struct clk *), GFP_KERNEL); if (!clk_data->clks) { diff --git a/drivers/clk/st/clkgen-pll.c b/drivers/clk/st/clkgen-pll.c index 25bda48a5d35..7a7106dc80bf 100644 --- a/drivers/clk/st/clkgen-pll.c +++ b/drivers/clk/st/clkgen-pll.c @@ -738,7 +738,7 @@ static void __init clkgen_c32_pll_setup(struct device_node *np, return; clk_data->clk_num = num_odfs; - clk_data->clks = kzalloc(clk_data->clk_num * sizeof(struct clk *), + clk_data->clks = kcalloc(clk_data->clk_num, sizeof(struct clk *), GFP_KERNEL); if (!clk_data->clks) diff --git a/drivers/clk/sunxi/clk-usb.c b/drivers/clk/sunxi/clk-usb.c index fe0c3d169377..917fc27a33dd 100644 --- a/drivers/clk/sunxi/clk-usb.c +++ b/drivers/clk/sunxi/clk-usb.c @@ -122,7 +122,7 @@ static void __init sunxi_usb_clk_setup(struct device_node *node, if (!clk_data) return; - clk_data->clks = kzalloc((qty+1) * sizeof(struct clk *), GFP_KERNEL); + clk_data->clks = kcalloc(qty + 1, sizeof(struct clk *), GFP_KERNEL); if (!clk_data->clks) { kfree(clk_data); return; diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c index 593d76a114f9..ffaf17f71860 100644 --- a/drivers/clk/tegra/clk.c +++ b/drivers/clk/tegra/clk.c @@ -216,14 +216,15 @@ struct clk ** __init tegra_clk_init(void __iomem *regs, int num, int banks) if (WARN_ON(banks > ARRAY_SIZE(periph_regs))) return NULL; - periph_clk_enb_refcnt = kzalloc(32 * banks * - sizeof(*periph_clk_enb_refcnt), GFP_KERNEL); + periph_clk_enb_refcnt = kcalloc(32 * banks, + sizeof(*periph_clk_enb_refcnt), + GFP_KERNEL); if (!periph_clk_enb_refcnt) return NULL; periph_banks = banks; - clks = kzalloc(num * sizeof(struct clk *), GFP_KERNEL); + clks = kcalloc(num, sizeof(struct clk *), GFP_KERNEL); if (!clks) kfree(periph_clk_enb_refcnt); diff --git a/drivers/clk/ti/adpll.c b/drivers/clk/ti/adpll.c index d6036c788fab..688e403333b9 100644 --- a/drivers/clk/ti/adpll.c +++ b/drivers/clk/ti/adpll.c @@ -501,8 +501,9 @@ static int ti_adpll_init_dco(struct ti_adpll_data *d) const char *postfix; int width, err; - d->outputs.clks = devm_kzalloc(d->dev, sizeof(struct clk *) * + d->outputs.clks = devm_kcalloc(d->dev, MAX_ADPLL_OUTPUTS, + sizeof(struct clk *), GFP_KERNEL); if (!d->outputs.clks) return -ENOMEM; @@ -915,8 +916,9 @@ static int ti_adpll_probe(struct platform_device *pdev) if (err) return err; - d->clocks = devm_kzalloc(d->dev, sizeof(struct ti_adpll_clock) * + d->clocks = devm_kcalloc(d->dev, TI_ADPLL_NR_CLOCKS, + sizeof(struct ti_adpll_clock), GFP_KERNEL); if (!d->clocks) return -ENOMEM; diff --git a/drivers/clk/ti/apll.c b/drivers/clk/ti/apll.c index 9498e9363b57..61c126a5d26a 100644 --- a/drivers/clk/ti/apll.c +++ b/drivers/clk/ti/apll.c @@ -206,7 +206,7 @@ static void __init of_dra7_apll_setup(struct device_node *node) goto cleanup; } - parent_names = kzalloc(sizeof(char *) * init->num_parents, GFP_KERNEL); + parent_names = kcalloc(init->num_parents, sizeof(char *), GFP_KERNEL); if (!parent_names) goto cleanup; diff --git a/drivers/clk/ti/divider.c b/drivers/clk/ti/divider.c index aaa277dd6d99..ccfb4d9a152a 100644 --- a/drivers/clk/ti/divider.c +++ b/drivers/clk/ti/divider.c @@ -366,7 +366,7 @@ int ti_clk_parse_divider_data(int *div_table, int num_dividers, int max_div, num_dividers = i; - tmp = kzalloc(sizeof(*tmp) * (valid_div + 1), GFP_KERNEL); + tmp = kcalloc(valid_div + 1, sizeof(*tmp), GFP_KERNEL); if (!tmp) return -ENOMEM; @@ -496,7 +496,7 @@ __init ti_clk_get_div_table(struct device_node *node) return ERR_PTR(-EINVAL); } - table = kzalloc(sizeof(*table) * (valid_div + 1), GFP_KERNEL); + table = kcalloc(valid_div + 1, sizeof(*table), GFP_KERNEL); if (!table) return ERR_PTR(-ENOMEM); diff --git a/drivers/clk/ti/dpll.c b/drivers/clk/ti/dpll.c index 7d33ca9042cb..dc86d07d0921 100644 --- a/drivers/clk/ti/dpll.c +++ b/drivers/clk/ti/dpll.c @@ -309,7 +309,7 @@ static void __init of_ti_dpll_setup(struct device_node *node, goto cleanup; } - parent_names = kzalloc(sizeof(char *) * init->num_parents, GFP_KERNEL); + parent_names = kcalloc(init->num_parents, sizeof(char *), GFP_KERNEL); if (!parent_names) goto cleanup; diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index 70b3cf8e23d0..bbbf37c471a3 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c @@ -1000,7 +1000,7 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev) /* Allocate and setup the channels. */ cmt->num_channels = hweight8(cmt->hw_channels); - cmt->channels = kzalloc(cmt->num_channels * sizeof(*cmt->channels), + cmt->channels = kcalloc(cmt->num_channels, sizeof(*cmt->channels), GFP_KERNEL); if (cmt->channels == NULL) { ret = -ENOMEM; diff --git a/drivers/clocksource/sh_mtu2.c b/drivers/clocksource/sh_mtu2.c index 53aa7e92a7d7..6812e099b6a3 100644 --- a/drivers/clocksource/sh_mtu2.c +++ b/drivers/clocksource/sh_mtu2.c @@ -418,7 +418,7 @@ static int sh_mtu2_setup(struct sh_mtu2_device *mtu, /* Allocate and setup the channels. */ mtu->num_channels = 3; - mtu->channels = kzalloc(sizeof(*mtu->channels) * mtu->num_channels, + mtu->channels = kcalloc(mtu->num_channels, sizeof(*mtu->channels), GFP_KERNEL); if (mtu->channels == NULL) { ret = -ENOMEM; diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c index 31d881621e41..c74a6c543ca2 100644 --- a/drivers/clocksource/sh_tmu.c +++ b/drivers/clocksource/sh_tmu.c @@ -569,7 +569,7 @@ static int sh_tmu_setup(struct sh_tmu_device *tmu, struct platform_device *pdev) } /* Allocate and setup the channels. */ - tmu->channels = kzalloc(sizeof(*tmu->channels) * tmu->num_channels, + tmu->channels = kcalloc(tmu->num_channels, sizeof(*tmu->channels), GFP_KERNEL); if (tmu->channels == NULL) { ret = -ENOMEM; diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index c7ce928fbf1f..52f5f1a2040c 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -125,7 +125,7 @@ config ARM_OMAP2PLUS_CPUFREQ default ARCH_OMAP2PLUS config ARM_QCOM_CPUFREQ_KRYO - bool "Qualcomm Kryo based CPUFreq" + tristate "Qualcomm Kryo based CPUFreq" depends on ARM64 depends on QCOM_QFPROM depends on QCOM_SMEM diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index 9449657d72f0..b61f4ec43e06 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -465,8 +465,8 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy, return result; } -unsigned int acpi_cpufreq_fast_switch(struct cpufreq_policy *policy, - unsigned int target_freq) +static unsigned int acpi_cpufreq_fast_switch(struct cpufreq_policy *policy, + unsigned int target_freq) { struct acpi_cpufreq_data *data = policy->driver_data; struct acpi_processor_performance *perf; @@ -759,8 +759,8 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) goto err_unreg; } - freq_table = kzalloc(sizeof(*freq_table) * - (perf->state_count+1), GFP_KERNEL); + freq_table = kcalloc(perf->state_count + 1, sizeof(*freq_table), + GFP_KERNEL); if (!freq_table) { result = -ENOMEM; goto err_unreg; diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c index 1d7ef5fc1977..cf62a1f64dd7 100644 --- a/drivers/cpufreq/arm_big_little.c +++ b/drivers/cpufreq/arm_big_little.c @@ -280,7 +280,7 @@ static int merge_cluster_tables(void) for (i = 0; i < MAX_CLUSTERS; i++) count += get_table_count(freq_table[i]); - table = kzalloc(sizeof(*table) * count, GFP_KERNEL); + table = kcalloc(count, sizeof(*table), GFP_KERNEL); if (!table) return -ENOMEM; diff --git a/drivers/cpufreq/bmips-cpufreq.c b/drivers/cpufreq/bmips-cpufreq.c index 1653151b77df..56a4ebbf00e0 100644 --- a/drivers/cpufreq/bmips-cpufreq.c +++ b/drivers/cpufreq/bmips-cpufreq.c @@ -71,7 +71,7 @@ bmips_cpufreq_get_freq_table(const struct cpufreq_policy *policy) cpu_freq = htp_freq_to_cpu_freq(priv->clk_mult); - table = kmalloc((priv->max_freqs + 1) * sizeof(*table), GFP_KERNEL); + table = kmalloc_array(priv->max_freqs + 1, sizeof(*table), GFP_KERNEL); if (!table) return ERR_PTR(-ENOMEM); diff --git a/drivers/cpufreq/brcmstb-avs-cpufreq.c b/drivers/cpufreq/brcmstb-avs-cpufreq.c index b07559b9ed99..e6f9cbe5835f 100644 --- a/drivers/cpufreq/brcmstb-avs-cpufreq.c +++ b/drivers/cpufreq/brcmstb-avs-cpufreq.c @@ -410,7 +410,7 @@ brcm_avs_get_freq_table(struct device *dev, struct private_data *priv) if (ret) return ERR_PTR(ret); - table = devm_kzalloc(dev, (AVS_PSTATE_MAX + 1) * sizeof(*table), + table = devm_kcalloc(dev, AVS_PSTATE_MAX + 1, sizeof(*table), GFP_KERNEL); if (!table) return ERR_PTR(-ENOMEM); diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c index 3464580ac3ca..a9d3eec32795 100644 --- a/drivers/cpufreq/cppc_cpufreq.c +++ b/drivers/cpufreq/cppc_cpufreq.c @@ -313,7 +313,8 @@ static int __init cppc_cpufreq_init(void) if (acpi_disabled) return -ENODEV; - all_cpu_data = kzalloc(sizeof(void *) * num_possible_cpus(), GFP_KERNEL); + all_cpu_data = kcalloc(num_possible_cpus(), sizeof(void *), + GFP_KERNEL); if (!all_cpu_data) return -ENOMEM; diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 871bf9cf55cf..1d50e97d49f1 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -165,7 +165,7 @@ unsigned int dbs_update(struct cpufreq_policy *policy) * calls, so the previous load value can be used then. */ load = j_cdbs->prev_load; - } else if (unlikely(time_elapsed > 2 * sampling_rate && + } else if (unlikely((int)idle_time > 2 * sampling_rate && j_cdbs->prev_load)) { /* * If the CPU had gone completely idle and a task has @@ -185,10 +185,8 @@ unsigned int dbs_update(struct cpufreq_policy *policy) * clear prev_load to guarantee that the load will be * computed again next time. * - * Detecting this situation is easy: the governor's - * utilization update handler would not have run during - * CPU-idle periods. Hence, an unusually large - * 'time_elapsed' (as compared to the sampling rate) + * Detecting this situation is easy: an unusually large + * 'idle_time' (as compared to the sampling rate) * indicates this scenario. */ load = j_cdbs->prev_load; @@ -217,8 +215,8 @@ unsigned int dbs_update(struct cpufreq_policy *policy) j_cdbs->prev_load = load; } - if (time_elapsed > 2 * sampling_rate) { - unsigned int periods = time_elapsed / sampling_rate; + if (unlikely((int)idle_time > 2 * sampling_rate)) { + unsigned int periods = idle_time / sampling_rate; if (periods < idle_periods) idle_periods = periods; diff --git a/drivers/cpufreq/ia64-acpi-cpufreq.c b/drivers/cpufreq/ia64-acpi-cpufreq.c index 7974a2fdb760..dd5440d3372d 100644 --- a/drivers/cpufreq/ia64-acpi-cpufreq.c +++ b/drivers/cpufreq/ia64-acpi-cpufreq.c @@ -241,8 +241,8 @@ acpi_cpufreq_cpu_init ( } /* alloc freq_table */ - freq_table = kzalloc(sizeof(*freq_table) * - (data->acpi_data.state_count + 1), + freq_table = kcalloc(data->acpi_data.state_count + 1, + sizeof(*freq_table), GFP_KERNEL); if (!freq_table) { result = -ENOMEM; diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c index 83cf631fc9bc..8b3c2a79ad6c 100644 --- a/drivers/cpufreq/imx6q-cpufreq.c +++ b/drivers/cpufreq/imx6q-cpufreq.c @@ -266,6 +266,8 @@ put_node: } #define OCOTP_CFG3_6UL_SPEED_696MHZ 0x2 +#define OCOTP_CFG3_6ULL_SPEED_792MHZ 0x2 +#define OCOTP_CFG3_6ULL_SPEED_900MHZ 0x3 static void imx6ul_opp_check_speed_grading(struct device *dev) { @@ -287,16 +289,30 @@ static void imx6ul_opp_check_speed_grading(struct device *dev) * Speed GRADING[1:0] defines the max speed of ARM: * 2b'00: Reserved; * 2b'01: 528000000Hz; - * 2b'10: 696000000Hz; - * 2b'11: Reserved; + * 2b'10: 696000000Hz on i.MX6UL, 792000000Hz on i.MX6ULL; + * 2b'11: 900000000Hz on i.MX6ULL only; * We need to set the max speed of ARM according to fuse map. */ val = readl_relaxed(base + OCOTP_CFG3); val >>= OCOTP_CFG3_SPEED_SHIFT; val &= 0x3; - if (val != OCOTP_CFG3_6UL_SPEED_696MHZ) - if (dev_pm_opp_disable(dev, 696000000)) - dev_warn(dev, "failed to disable 696MHz OPP\n"); + + if (of_machine_is_compatible("fsl,imx6ul")) { + if (val != OCOTP_CFG3_6UL_SPEED_696MHZ) + if (dev_pm_opp_disable(dev, 696000000)) + dev_warn(dev, "failed to disable 696MHz OPP\n"); + } + + if (of_machine_is_compatible("fsl,imx6ull")) { + if (val != OCOTP_CFG3_6ULL_SPEED_792MHZ) + if (dev_pm_opp_disable(dev, 792000000)) + dev_warn(dev, "failed to disable 792MHz OPP\n"); + + if (val != OCOTP_CFG3_6ULL_SPEED_900MHZ) + if (dev_pm_opp_disable(dev, 900000000)) + dev_warn(dev, "failed to disable 900MHz OPP\n"); + } + iounmap(base); put_node: of_node_put(np); @@ -356,7 +372,8 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev) goto put_reg; } - if (of_machine_is_compatible("fsl,imx6ul")) + if (of_machine_is_compatible("fsl,imx6ul") || + of_machine_is_compatible("fsl,imx6ull")) imx6ul_opp_check_speed_grading(cpu_dev); else imx6q_opp_check_speed_grading(cpu_dev); @@ -377,7 +394,8 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev) } /* Make imx6_soc_volt array's size same as arm opp number */ - imx6_soc_volt = devm_kzalloc(cpu_dev, sizeof(*imx6_soc_volt) * num, GFP_KERNEL); + imx6_soc_volt = devm_kcalloc(cpu_dev, num, sizeof(*imx6_soc_volt), + GFP_KERNEL); if (imx6_soc_volt == NULL) { ret = -ENOMEM; goto free_freq_table; diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 08960a55eb27..1de5ec8d5ea3 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -221,6 +221,11 @@ struct global_params { * preference/bias * @epp_saved: Saved EPP/EPB during system suspend or CPU offline * operation + * @hwp_req_cached: Cached value of the last HWP Request MSR + * @hwp_cap_cached: Cached value of the last HWP Capabilities MSR + * @last_io_update: Last time when IO wake flag was set + * @sched_flags: Store scheduler flags for possible cross CPU update + * @hwp_boost_min: Last HWP boosted min performance * * This structure stores per CPU instance data for all CPUs. */ @@ -253,6 +258,11 @@ struct cpudata { s16 epp_policy; s16 epp_default; s16 epp_saved; + u64 hwp_req_cached; + u64 hwp_cap_cached; + u64 last_io_update; + unsigned int sched_flags; + u32 hwp_boost_min; }; static struct cpudata **all_cpu_data; @@ -285,6 +295,7 @@ static struct pstate_funcs pstate_funcs __read_mostly; static int hwp_active __read_mostly; static bool per_cpu_limits __read_mostly; +static bool hwp_boost __read_mostly; static struct cpufreq_driver *intel_pstate_driver __read_mostly; @@ -689,6 +700,7 @@ static void intel_pstate_get_hwp_max(unsigned int cpu, int *phy_max, u64 cap; rdmsrl_on_cpu(cpu, MSR_HWP_CAPABILITIES, &cap); + WRITE_ONCE(all_cpu_data[cpu]->hwp_cap_cached, cap); if (global.no_turbo) *current_max = HWP_GUARANTEED_PERF(cap); else @@ -763,6 +775,7 @@ update_epp: intel_pstate_set_epb(cpu, epp); } skip_epp: + WRITE_ONCE(cpu_data->hwp_req_cached, value); wrmsrl_on_cpu(cpu, MSR_HWP_REQUEST, value); } @@ -1020,6 +1033,30 @@ static ssize_t store_min_perf_pct(struct kobject *a, struct attribute *b, return count; } +static ssize_t show_hwp_dynamic_boost(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", hwp_boost); +} + +static ssize_t store_hwp_dynamic_boost(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + + ret = kstrtouint(buf, 10, &input); + if (ret) + return ret; + + mutex_lock(&intel_pstate_driver_lock); + hwp_boost = !!input; + intel_pstate_update_policies(); + mutex_unlock(&intel_pstate_driver_lock); + + return count; +} + show_one(max_perf_pct, max_perf_pct); show_one(min_perf_pct, min_perf_pct); @@ -1029,6 +1066,7 @@ define_one_global_rw(max_perf_pct); define_one_global_rw(min_perf_pct); define_one_global_ro(turbo_pct); define_one_global_ro(num_pstates); +define_one_global_rw(hwp_dynamic_boost); static struct attribute *intel_pstate_attributes[] = { &status.attr, @@ -1069,6 +1107,11 @@ static void __init intel_pstate_sysfs_expose_params(void) rc = sysfs_create_file(intel_pstate_kobject, &min_perf_pct.attr); WARN_ON(rc); + if (hwp_active) { + rc = sysfs_create_file(intel_pstate_kobject, + &hwp_dynamic_boost.attr); + WARN_ON(rc); + } } /************************** sysfs end ************************/ @@ -1381,6 +1424,116 @@ static void intel_pstate_get_cpu_pstates(struct cpudata *cpu) intel_pstate_set_min_pstate(cpu); } +/* + * Long hold time will keep high perf limits for long time, + * which negatively impacts perf/watt for some workloads, + * like specpower. 3ms is based on experiements on some + * workoads. + */ +static int hwp_boost_hold_time_ns = 3 * NSEC_PER_MSEC; + +static inline void intel_pstate_hwp_boost_up(struct cpudata *cpu) +{ + u64 hwp_req = READ_ONCE(cpu->hwp_req_cached); + u32 max_limit = (hwp_req & 0xff00) >> 8; + u32 min_limit = (hwp_req & 0xff); + u32 boost_level1; + + /* + * Cases to consider (User changes via sysfs or boot time): + * If, P0 (Turbo max) = P1 (Guaranteed max) = min: + * No boost, return. + * If, P0 (Turbo max) > P1 (Guaranteed max) = min: + * Should result in one level boost only for P0. + * If, P0 (Turbo max) = P1 (Guaranteed max) > min: + * Should result in two level boost: + * (min + p1)/2 and P1. + * If, P0 (Turbo max) > P1 (Guaranteed max) > min: + * Should result in three level boost: + * (min + p1)/2, P1 and P0. + */ + + /* If max and min are equal or already at max, nothing to boost */ + if (max_limit == min_limit || cpu->hwp_boost_min >= max_limit) + return; + + if (!cpu->hwp_boost_min) + cpu->hwp_boost_min = min_limit; + + /* level at half way mark between min and guranteed */ + boost_level1 = (HWP_GUARANTEED_PERF(cpu->hwp_cap_cached) + min_limit) >> 1; + + if (cpu->hwp_boost_min < boost_level1) + cpu->hwp_boost_min = boost_level1; + else if (cpu->hwp_boost_min < HWP_GUARANTEED_PERF(cpu->hwp_cap_cached)) + cpu->hwp_boost_min = HWP_GUARANTEED_PERF(cpu->hwp_cap_cached); + else if (cpu->hwp_boost_min == HWP_GUARANTEED_PERF(cpu->hwp_cap_cached) && + max_limit != HWP_GUARANTEED_PERF(cpu->hwp_cap_cached)) + cpu->hwp_boost_min = max_limit; + else + return; + + hwp_req = (hwp_req & ~GENMASK_ULL(7, 0)) | cpu->hwp_boost_min; + wrmsrl(MSR_HWP_REQUEST, hwp_req); + cpu->last_update = cpu->sample.time; +} + +static inline void intel_pstate_hwp_boost_down(struct cpudata *cpu) +{ + if (cpu->hwp_boost_min) { + bool expired; + + /* Check if we are idle for hold time to boost down */ + expired = time_after64(cpu->sample.time, cpu->last_update + + hwp_boost_hold_time_ns); + if (expired) { + wrmsrl(MSR_HWP_REQUEST, cpu->hwp_req_cached); + cpu->hwp_boost_min = 0; + } + } + cpu->last_update = cpu->sample.time; +} + +static inline void intel_pstate_update_util_hwp_local(struct cpudata *cpu, + u64 time) +{ + cpu->sample.time = time; + + if (cpu->sched_flags & SCHED_CPUFREQ_IOWAIT) { + bool do_io = false; + + cpu->sched_flags = 0; + /* + * Set iowait_boost flag and update time. Since IO WAIT flag + * is set all the time, we can't just conclude that there is + * some IO bound activity is scheduled on this CPU with just + * one occurrence. If we receive at least two in two + * consecutive ticks, then we treat as boost candidate. + */ + if (time_before64(time, cpu->last_io_update + 2 * TICK_NSEC)) + do_io = true; + + cpu->last_io_update = time; + + if (do_io) + intel_pstate_hwp_boost_up(cpu); + + } else { + intel_pstate_hwp_boost_down(cpu); + } +} + +static inline void intel_pstate_update_util_hwp(struct update_util_data *data, + u64 time, unsigned int flags) +{ + struct cpudata *cpu = container_of(data, struct cpudata, update_util); + + cpu->sched_flags |= flags; + + if (smp_processor_id() == cpu->cpu) + intel_pstate_update_util_hwp_local(cpu, time); +} + static inline void intel_pstate_calc_avg_perf(struct cpudata *cpu) { struct sample *sample = &cpu->sample; @@ -1641,6 +1794,12 @@ static const struct x86_cpu_id intel_pstate_cpu_ee_disable_ids[] = { {} }; +static const struct x86_cpu_id intel_pstate_hwp_boost_ids[] = { + ICPU(INTEL_FAM6_SKYLAKE_X, core_funcs), + ICPU(INTEL_FAM6_SKYLAKE_DESKTOP, core_funcs), + {} +}; + static int intel_pstate_init_cpu(unsigned int cpunum) { struct cpudata *cpu; @@ -1671,6 +1830,10 @@ static int intel_pstate_init_cpu(unsigned int cpunum) intel_pstate_disable_ee(cpunum); intel_pstate_hwp_enable(cpu); + + id = x86_match_cpu(intel_pstate_hwp_boost_ids); + if (id) + hwp_boost = true; } intel_pstate_get_cpu_pstates(cpu); @@ -1684,7 +1847,7 @@ static void intel_pstate_set_update_util_hook(unsigned int cpu_num) { struct cpudata *cpu = all_cpu_data[cpu_num]; - if (hwp_active) + if (hwp_active && !hwp_boost) return; if (cpu->update_util_set) @@ -1693,7 +1856,9 @@ static void intel_pstate_set_update_util_hook(unsigned int cpu_num) /* Prevent intel_pstate_update_util() from using stale data. */ cpu->sample.time = 0; cpufreq_add_update_util_hook(cpu_num, &cpu->update_util, - intel_pstate_update_util); + (hwp_active ? + intel_pstate_update_util_hwp : + intel_pstate_update_util)); cpu->update_util_set = true; } @@ -1805,8 +1970,16 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy) intel_pstate_set_update_util_hook(policy->cpu); } - if (hwp_active) + if (hwp_active) { + /* + * When hwp_boost was active before and dynamically it + * was turned off, in that case we need to clear the + * update util hook. + */ + if (!hwp_boost) + intel_pstate_clear_update_util_hook(policy->cpu); intel_pstate_hwp_set(policy->cpu); + } mutex_unlock(&intel_pstate_limits_lock); @@ -2339,7 +2512,7 @@ hwp_cpu_matched: pr_info("Intel P-state driver initializing\n"); - all_cpu_data = vzalloc(sizeof(void *) * num_possible_cpus()); + all_cpu_data = vzalloc(array_size(sizeof(void *), num_possible_cpus())); if (!all_cpu_data) return -ENOMEM; diff --git a/drivers/cpufreq/longhaul.c b/drivers/cpufreq/longhaul.c index 61a4c5b08219..279bd9e9fa95 100644 --- a/drivers/cpufreq/longhaul.c +++ b/drivers/cpufreq/longhaul.c @@ -474,8 +474,8 @@ static int longhaul_get_ranges(void) return -EINVAL; } - longhaul_table = kzalloc((numscales + 1) * sizeof(*longhaul_table), - GFP_KERNEL); + longhaul_table = kcalloc(numscales + 1, sizeof(*longhaul_table), + GFP_KERNEL); if (!longhaul_table) return -ENOMEM; diff --git a/drivers/cpufreq/pxa3xx-cpufreq.c b/drivers/cpufreq/pxa3xx-cpufreq.c index 7acc7fa4536d..9daa2cc318bb 100644 --- a/drivers/cpufreq/pxa3xx-cpufreq.c +++ b/drivers/cpufreq/pxa3xx-cpufreq.c @@ -93,7 +93,7 @@ static int setup_freqs_table(struct cpufreq_policy *policy, struct cpufreq_frequency_table *table; int i; - table = kzalloc((num + 1) * sizeof(*table), GFP_KERNEL); + table = kcalloc(num + 1, sizeof(*table), GFP_KERNEL); if (table == NULL) return -ENOMEM; diff --git a/drivers/cpufreq/s3c24xx-cpufreq.c b/drivers/cpufreq/s3c24xx-cpufreq.c index 909bd6e27639..3b291a2b0cb3 100644 --- a/drivers/cpufreq/s3c24xx-cpufreq.c +++ b/drivers/cpufreq/s3c24xx-cpufreq.c @@ -562,7 +562,7 @@ static int s3c_cpufreq_build_freq(void) size = cpu_cur.info->calc_freqtable(&cpu_cur, NULL, 0); size++; - ftab = kzalloc(sizeof(*ftab) * size, GFP_KERNEL); + ftab = kcalloc(size, sizeof(*ftab), GFP_KERNEL); if (!ftab) return -ENOMEM; diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c index b4dbc77459b6..50b1551ba894 100644 --- a/drivers/cpufreq/scmi-cpufreq.c +++ b/drivers/cpufreq/scmi-cpufreq.c @@ -117,7 +117,7 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy) return -ENODEV; } - ret = handle->perf_ops->add_opps_to_device(handle, cpu_dev); + ret = handle->perf_ops->device_opps_add(handle, cpu_dev); if (ret) { dev_warn(cpu_dev, "failed to add opps to the device\n"); return ret; @@ -164,7 +164,7 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy) /* SCMI allows DVFS request for any domain from any CPU */ policy->dvfs_possible_from_any_cpu = true; - latency = handle->perf_ops->get_transition_latency(handle, cpu_dev); + latency = handle->perf_ops->transition_latency_get(handle, cpu_dev); if (!latency) latency = CPUFREQ_ETERNAL; diff --git a/drivers/cpufreq/sfi-cpufreq.c b/drivers/cpufreq/sfi-cpufreq.c index 9767afe05da2..978770432b13 100644 --- a/drivers/cpufreq/sfi-cpufreq.c +++ b/drivers/cpufreq/sfi-cpufreq.c @@ -95,8 +95,8 @@ static int __init sfi_cpufreq_init(void) if (ret) return ret; - freq_table = kzalloc(sizeof(*freq_table) * - (num_freq_table_entries + 1), GFP_KERNEL); + freq_table = kcalloc(num_freq_table_entries + 1, sizeof(*freq_table), + GFP_KERNEL); if (!freq_table) { ret = -ENOMEM; goto err_free_array; diff --git a/drivers/cpufreq/spear-cpufreq.c b/drivers/cpufreq/spear-cpufreq.c index 195f27f9c1cb..4074e2615522 100644 --- a/drivers/cpufreq/spear-cpufreq.c +++ b/drivers/cpufreq/spear-cpufreq.c @@ -195,7 +195,7 @@ static int spear_cpufreq_probe(struct platform_device *pdev) cnt = prop->length / sizeof(u32); val = prop->value; - freq_tbl = kzalloc(sizeof(*freq_tbl) * (cnt + 1), GFP_KERNEL); + freq_tbl = kcalloc(cnt + 1, sizeof(*freq_tbl), GFP_KERNEL); if (!freq_tbl) { ret = -ENOMEM; goto out_put_node; diff --git a/drivers/cpufreq/ti-cpufreq.c b/drivers/cpufreq/ti-cpufreq.c index 6ba709b6f095..3f0e2a14895a 100644 --- a/drivers/cpufreq/ti-cpufreq.c +++ b/drivers/cpufreq/ti-cpufreq.c @@ -217,7 +217,7 @@ static int ti_cpufreq_probe(struct platform_device *pdev) if (!match) return -ENODEV; - opp_data = kzalloc(sizeof(*opp_data), GFP_KERNEL); + opp_data = devm_kzalloc(&pdev->dev, sizeof(*opp_data), GFP_KERNEL); if (!opp_data) return -ENOMEM; @@ -226,8 +226,7 @@ static int ti_cpufreq_probe(struct platform_device *pdev) opp_data->cpu_dev = get_cpu_device(0); if (!opp_data->cpu_dev) { pr_err("%s: Failed to get device for CPU0\n", __func__); - ret = ENODEV; - goto free_opp_data; + return -ENODEV; } opp_data->opp_node = dev_pm_opp_of_get_opp_desc_node(opp_data->cpu_dev); @@ -285,8 +284,6 @@ register_cpufreq_dt: fail_put_node: of_node_put(opp_data->opp_node); -free_opp_data: - kfree(opp_data); return ret; } diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c index 9cb234c72549..05981ccd9901 100644 --- a/drivers/crypto/amcc/crypto4xx_core.c +++ b/drivers/crypto/amcc/crypto4xx_core.c @@ -141,11 +141,11 @@ static void crypto4xx_hw_init(struct crypto4xx_device *dev) int crypto4xx_alloc_sa(struct crypto4xx_ctx *ctx, u32 size) { - ctx->sa_in = kzalloc(size * 4, GFP_ATOMIC); + ctx->sa_in = kcalloc(size, 4, GFP_ATOMIC); if (ctx->sa_in == NULL) return -ENOMEM; - ctx->sa_out = kzalloc(size * 4, GFP_ATOMIC); + ctx->sa_out = kcalloc(size, 4, GFP_ATOMIC); if (ctx->sa_out == NULL) { kfree(ctx->sa_in); ctx->sa_in = NULL; @@ -180,8 +180,8 @@ static u32 crypto4xx_build_pdr(struct crypto4xx_device *dev) if (!dev->pdr) return -ENOMEM; - dev->pdr_uinfo = kzalloc(sizeof(struct pd_uinfo) * PPC4XX_NUM_PD, - GFP_KERNEL); + dev->pdr_uinfo = kcalloc(PPC4XX_NUM_PD, sizeof(struct pd_uinfo), + GFP_KERNEL); if (!dev->pdr_uinfo) { dma_free_coherent(dev->core_dev->device, sizeof(struct ce_pd) * PPC4XX_NUM_PD, diff --git a/drivers/crypto/cavium/nitrox/nitrox_isr.c b/drivers/crypto/cavium/nitrox/nitrox_isr.c index dbead5f45df3..ee0d70ba25d5 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_isr.c +++ b/drivers/crypto/cavium/nitrox/nitrox_isr.c @@ -254,7 +254,7 @@ static int nitrox_enable_msix(struct nitrox_device *ndev) * Entry 192: NPS_CORE_INT_ACTIVE */ nr_entries = (ndev->nr_queues * NR_RING_VECTORS) + 1; - entries = kzalloc_node(nr_entries * sizeof(struct msix_entry), + entries = kcalloc_node(nr_entries, sizeof(struct msix_entry), GFP_KERNEL, ndev->node); if (!entries) return -ENOMEM; diff --git a/drivers/crypto/chelsio/chtls/chtls_io.c b/drivers/crypto/chelsio/chtls/chtls_io.c index 51fc6821cbbf..00c7aab8e7d0 100644 --- a/drivers/crypto/chelsio/chtls/chtls_io.c +++ b/drivers/crypto/chelsio/chtls/chtls_io.c @@ -240,7 +240,7 @@ static int tls_copy_ivs(struct sock *sk, struct sk_buff *skb) } /* generate the IVs */ - ivs = kmalloc(number_of_ivs * CIPHER_BLOCK_SIZE, GFP_ATOMIC); + ivs = kmalloc_array(CIPHER_BLOCK_SIZE, number_of_ivs, GFP_ATOMIC); if (!ivs) return -ENOMEM; get_random_bytes(ivs, number_of_ivs * CIPHER_BLOCK_SIZE); diff --git a/drivers/crypto/inside-secure/safexcel_hash.c b/drivers/crypto/inside-secure/safexcel_hash.c index d138d6b8fec5..c77b0e1655a8 100644 --- a/drivers/crypto/inside-secure/safexcel_hash.c +++ b/drivers/crypto/inside-secure/safexcel_hash.c @@ -922,7 +922,7 @@ int safexcel_hmac_setkey(const char *alg, const u8 *key, unsigned int keylen, crypto_ahash_clear_flags(tfm, ~0); blocksize = crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm)); - ipad = kzalloc(2 * blocksize, GFP_KERNEL); + ipad = kcalloc(2, blocksize, GFP_KERNEL); if (!ipad) { ret = -ENOMEM; goto free_request; diff --git a/drivers/crypto/marvell/cesa.c b/drivers/crypto/marvell/cesa.c index f81fa4a3e66b..a4aa6813de4b 100644 --- a/drivers/crypto/marvell/cesa.c +++ b/drivers/crypto/marvell/cesa.c @@ -471,7 +471,7 @@ static int mv_cesa_probe(struct platform_device *pdev) sram_size = CESA_SA_MIN_SRAM_SIZE; cesa->sram_size = sram_size; - cesa->engines = devm_kzalloc(dev, caps->nengines * sizeof(*engines), + cesa->engines = devm_kcalloc(dev, caps->nengines, sizeof(*engines), GFP_KERNEL); if (!cesa->engines) return -ENOMEM; diff --git a/drivers/crypto/marvell/hash.c b/drivers/crypto/marvell/hash.c index e61b08566093..e34d80b6b7e5 100644 --- a/drivers/crypto/marvell/hash.c +++ b/drivers/crypto/marvell/hash.c @@ -1198,7 +1198,7 @@ static int mv_cesa_ahmac_setkey(const char *hash_alg_name, blocksize = crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm)); - ipad = kzalloc(2 * blocksize, GFP_KERNEL); + ipad = kcalloc(2, blocksize, GFP_KERNEL); if (!ipad) { ret = -ENOMEM; goto free_req; diff --git a/drivers/crypto/n2_core.c b/drivers/crypto/n2_core.c index 80e9c842aad4..ab6235b7ff22 100644 --- a/drivers/crypto/n2_core.c +++ b/drivers/crypto/n2_core.c @@ -1919,12 +1919,12 @@ static int grab_global_resources(void) goto out_hvapi_release; err = -ENOMEM; - cpu_to_cwq = kzalloc(sizeof(struct spu_queue *) * NR_CPUS, + cpu_to_cwq = kcalloc(NR_CPUS, sizeof(struct spu_queue *), GFP_KERNEL); if (!cpu_to_cwq) goto out_queue_cache_destroy; - cpu_to_mau = kzalloc(sizeof(struct spu_queue *) * NR_CPUS, + cpu_to_mau = kcalloc(NR_CPUS, sizeof(struct spu_queue *), GFP_KERNEL); if (!cpu_to_mau) goto out_free_cwq_table; diff --git a/drivers/crypto/qat/qat_common/adf_isr.c b/drivers/crypto/qat/qat_common/adf_isr.c index 06d49017a52b..cd1cdf5305bc 100644 --- a/drivers/crypto/qat/qat_common/adf_isr.c +++ b/drivers/crypto/qat/qat_common/adf_isr.c @@ -238,7 +238,7 @@ static int adf_isr_alloc_msix_entry_table(struct adf_accel_dev *accel_dev) if (!accel_dev->pf.vf_info) msix_num_entries += hw_data->num_banks; - entries = kzalloc_node(msix_num_entries * sizeof(*entries), + entries = kcalloc_node(msix_num_entries, sizeof(*entries), GFP_KERNEL, dev_to_node(&GET_DEV(accel_dev))); if (!entries) return -ENOMEM; diff --git a/drivers/crypto/qat/qat_common/qat_uclo.c b/drivers/crypto/qat/qat_common/qat_uclo.c index 98d22c2096e3..6bd8f6a2a24f 100644 --- a/drivers/crypto/qat/qat_common/qat_uclo.c +++ b/drivers/crypto/qat/qat_common/qat_uclo.c @@ -1162,8 +1162,9 @@ static int qat_uclo_map_suof(struct icp_qat_fw_loader_handle *handle, suof_handle->img_table.num_simgs = suof_ptr->num_chunks - 1; if (suof_handle->img_table.num_simgs != 0) { - suof_img_hdr = kzalloc(suof_handle->img_table.num_simgs * - sizeof(img_header), GFP_KERNEL); + suof_img_hdr = kcalloc(suof_handle->img_table.num_simgs, + sizeof(img_header), + GFP_KERNEL); if (!suof_img_hdr) return -ENOMEM; suof_handle->img_table.simg_hdr = suof_img_hdr; diff --git a/drivers/crypto/stm32/stm32-hash.c b/drivers/crypto/stm32/stm32-hash.c index 981e45692695..cdc96f1bb917 100644 --- a/drivers/crypto/stm32/stm32-hash.c +++ b/drivers/crypto/stm32/stm32-hash.c @@ -970,8 +970,9 @@ static int stm32_hash_export(struct ahash_request *req, void *out) while (!(stm32_hash_read(hdev, HASH_SR) & HASH_SR_DATA_INPUT_READY)) cpu_relax(); - rctx->hw_context = kmalloc(sizeof(u32) * (3 + HASH_CSR_REGISTER_NUMBER), - GFP_KERNEL); + rctx->hw_context = kmalloc_array(3 + HASH_CSR_REGISTER_NUMBER, + sizeof(u32), + GFP_KERNEL); preg = rctx->hw_context; diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 7cebf0a6ffbc..cf14f099ce4a 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -3393,8 +3393,10 @@ static int talitos_probe(struct platform_device *ofdev) } } - priv->chan = devm_kzalloc(dev, sizeof(struct talitos_channel) * - priv->num_channels, GFP_KERNEL); + priv->chan = devm_kcalloc(dev, + priv->num_channels, + sizeof(struct talitos_channel), + GFP_KERNEL); if (!priv->chan) { dev_err(dev, "failed to allocate channel management space\n"); err = -ENOMEM; @@ -3411,9 +3413,10 @@ static int talitos_probe(struct platform_device *ofdev) spin_lock_init(&priv->chan[i].head_lock); spin_lock_init(&priv->chan[i].tail_lock); - priv->chan[i].fifo = devm_kzalloc(dev, - sizeof(struct talitos_request) * - priv->fifo_len, GFP_KERNEL); + priv->chan[i].fifo = devm_kcalloc(dev, + priv->fifo_len, + sizeof(struct talitos_request), + GFP_KERNEL); if (!priv->chan[i].fifo) { dev_err(dev, "failed to allocate request fifo %d\n", i); err = -ENOMEM; diff --git a/drivers/crypto/virtio/virtio_crypto_algs.c b/drivers/crypto/virtio/virtio_crypto_algs.c index ba190cfa7aa1..af6a908dfa7a 100644 --- a/drivers/crypto/virtio/virtio_crypto_algs.c +++ b/drivers/crypto/virtio/virtio_crypto_algs.c @@ -371,7 +371,7 @@ __virtio_crypto_ablkcipher_do_req(struct virtio_crypto_sym_request *vc_sym_req, /* Why 3? outhdr + iv + inhdr */ sg_total = src_nents + dst_nents + 3; - sgs = kzalloc_node(sg_total * sizeof(*sgs), GFP_ATOMIC, + sgs = kcalloc_node(sg_total, sizeof(*sgs), GFP_ATOMIC, dev_to_node(&vcrypto->vdev->dev)); if (!sgs) return -ENOMEM; diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index fe2af6aa88fc..0b5b3abe054e 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -628,14 +628,15 @@ struct devfreq *devfreq_add_device(struct device *dev, goto err_dev; } - devfreq->trans_table = devm_kzalloc(&devfreq->dev, - sizeof(unsigned int) * - devfreq->profile->max_state * - devfreq->profile->max_state, - GFP_KERNEL); - devfreq->time_in_state = devm_kzalloc(&devfreq->dev, - sizeof(unsigned long) * + devfreq->trans_table = + devm_kzalloc(&devfreq->dev, + array3_size(sizeof(unsigned int), + devfreq->profile->max_state, + devfreq->profile->max_state), + GFP_KERNEL); + devfreq->time_in_state = devm_kcalloc(&devfreq->dev, devfreq->profile->max_state, + sizeof(unsigned long), GFP_KERNEL); devfreq->last_stat_updated = jiffies; diff --git a/drivers/devfreq/event/exynos-ppmu.c b/drivers/devfreq/event/exynos-ppmu.c index d96e3dc71cf8..3cd6a184fe7c 100644 --- a/drivers/devfreq/event/exynos-ppmu.c +++ b/drivers/devfreq/event/exynos-ppmu.c @@ -518,7 +518,7 @@ static int of_get_devfreq_events(struct device_node *np, event_ops = exynos_bus_get_ops(np); count = of_get_child_count(events_np); - desc = devm_kzalloc(dev, sizeof(*desc) * count, GFP_KERNEL); + desc = devm_kcalloc(dev, count, sizeof(*desc), GFP_KERNEL); if (!desc) return -ENOMEM; info->num_events = count; diff --git a/drivers/dma/bestcomm/bestcomm.c b/drivers/dma/bestcomm/bestcomm.c index 7a67b8345092..d91cbbe7a48f 100644 --- a/drivers/dma/bestcomm/bestcomm.c +++ b/drivers/dma/bestcomm/bestcomm.c @@ -87,7 +87,8 @@ bcom_task_alloc(int bd_count, int bd_size, int priv_size) /* Init the BDs, if needed */ if (bd_count) { - tsk->cookie = kmalloc(sizeof(void*) * bd_count, GFP_KERNEL); + tsk->cookie = kmalloc_array(bd_count, sizeof(void *), + GFP_KERNEL); if (!tsk->cookie) goto error; diff --git a/drivers/dma/ioat/init.c b/drivers/dma/ioat/init.c index 7792a9186f9c..4fa4c06c9edb 100644 --- a/drivers/dma/ioat/init.c +++ b/drivers/dma/ioat/init.c @@ -322,10 +322,10 @@ static int ioat_dma_self_test(struct ioatdma_device *ioat_dma) unsigned long tmo; unsigned long flags; - src = kzalloc(sizeof(u8) * IOAT_TEST_SIZE, GFP_KERNEL); + src = kzalloc(IOAT_TEST_SIZE, GFP_KERNEL); if (!src) return -ENOMEM; - dest = kzalloc(sizeof(u8) * IOAT_TEST_SIZE, GFP_KERNEL); + dest = kzalloc(IOAT_TEST_SIZE, GFP_KERNEL); if (!dest) { kfree(src); return -ENOMEM; diff --git a/drivers/dma/ipu/ipu_idmac.c b/drivers/dma/ipu/ipu_idmac.c index ed76044ce4b9..bbff52be4f0f 100644 --- a/drivers/dma/ipu/ipu_idmac.c +++ b/drivers/dma/ipu/ipu_idmac.c @@ -910,7 +910,8 @@ out: /* Called with ichan->chan_mutex held */ static int idmac_desc_alloc(struct idmac_channel *ichan, int n) { - struct idmac_tx_desc *desc = vmalloc(n * sizeof(struct idmac_tx_desc)); + struct idmac_tx_desc *desc = + vmalloc(array_size(n, sizeof(struct idmac_tx_desc))); struct idmac *idmac = to_idmac(ichan->dma_chan.device); if (!desc) diff --git a/drivers/dma/k3dma.c b/drivers/dma/k3dma.c index 26b67455208f..fa31cccbe04f 100644 --- a/drivers/dma/k3dma.c +++ b/drivers/dma/k3dma.c @@ -848,8 +848,8 @@ static int k3_dma_probe(struct platform_device *op) return -ENOMEM; /* init phy channel */ - d->phy = devm_kzalloc(&op->dev, - d->dma_channels * sizeof(struct k3_dma_phy), GFP_KERNEL); + d->phy = devm_kcalloc(&op->dev, + d->dma_channels, sizeof(struct k3_dma_phy), GFP_KERNEL); if (d->phy == NULL) return -ENOMEM; @@ -879,8 +879,8 @@ static int k3_dma_probe(struct platform_device *op) d->slave.copy_align = DMAENGINE_ALIGN_8_BYTES; /* init virtual channel */ - d->chans = devm_kzalloc(&op->dev, - d->dma_requests * sizeof(struct k3_dma_chan), GFP_KERNEL); + d->chans = devm_kcalloc(&op->dev, + d->dma_requests, sizeof(struct k3_dma_chan), GFP_KERNEL); if (d->chans == NULL) return -ENOMEM; diff --git a/drivers/dma/mic_x100_dma.c b/drivers/dma/mic_x100_dma.c index 94d7bd7d2880..68dd79783b54 100644 --- a/drivers/dma/mic_x100_dma.c +++ b/drivers/dma/mic_x100_dma.c @@ -385,7 +385,8 @@ static int mic_dma_alloc_desc_ring(struct mic_dma_chan *ch) if (dma_mapping_error(dev, ch->desc_ring_micpa)) goto map_error; - ch->tx_array = vzalloc(MIC_DMA_DESC_RX_SIZE * sizeof(*ch->tx_array)); + ch->tx_array = vzalloc(array_size(MIC_DMA_DESC_RX_SIZE, + sizeof(*ch->tx_array))); if (!ch->tx_array) goto tx_error; return 0; diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index 1993889003fd..969534c1a6c6 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -777,11 +777,11 @@ static int mv_chan_memcpy_self_test(struct mv_xor_chan *mv_chan) struct dmaengine_unmap_data *unmap; int err = 0; - src = kmalloc(sizeof(u8) * PAGE_SIZE, GFP_KERNEL); + src = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!src) return -ENOMEM; - dest = kzalloc(sizeof(u8) * PAGE_SIZE, GFP_KERNEL); + dest = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!dest) { kfree(src); return -ENOMEM; diff --git a/drivers/dma/mv_xor_v2.c b/drivers/dma/mv_xor_v2.c index 3548caa9e933..c6589ccf1b9a 100644 --- a/drivers/dma/mv_xor_v2.c +++ b/drivers/dma/mv_xor_v2.c @@ -809,8 +809,9 @@ static int mv_xor_v2_probe(struct platform_device *pdev) } /* alloc memory for the SW descriptors */ - xor_dev->sw_desq = devm_kzalloc(&pdev->dev, sizeof(*sw_desc) * - MV_XOR_V2_DESC_NUM, GFP_KERNEL); + xor_dev->sw_desq = devm_kcalloc(&pdev->dev, + MV_XOR_V2_DESC_NUM, sizeof(*sw_desc), + GFP_KERNEL); if (!xor_dev->sw_desq) { ret = -ENOMEM; goto free_hw_desq; diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 6237069001c4..defcdde4d358 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -1866,7 +1866,7 @@ static int dmac_alloc_threads(struct pl330_dmac *pl330) int i; /* Allocate 1 Manager and 'chans' Channel threads */ - pl330->channels = kzalloc((1 + chans) * sizeof(*thrd), + pl330->channels = kcalloc(1 + chans, sizeof(*thrd), GFP_KERNEL); if (!pl330->channels) return -ENOMEM; @@ -2990,7 +2990,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) pl330->num_peripherals = num_chan; - pl330->peripherals = kzalloc(num_chan * sizeof(*pch), GFP_KERNEL); + pl330->peripherals = kcalloc(num_chan, sizeof(*pch), GFP_KERNEL); if (!pl330->peripherals) { ret = -ENOMEM; goto probe_err2; diff --git a/drivers/dma/s3c24xx-dma.c b/drivers/dma/s3c24xx-dma.c index cd92d696bcf9..7056fe7513b4 100644 --- a/drivers/dma/s3c24xx-dma.c +++ b/drivers/dma/s3c24xx-dma.c @@ -1223,9 +1223,9 @@ static int s3c24xx_dma_probe(struct platform_device *pdev) if (IS_ERR(s3cdma->base)) return PTR_ERR(s3cdma->base); - s3cdma->phy_chans = devm_kzalloc(&pdev->dev, - sizeof(struct s3c24xx_dma_phy) * - pdata->num_phy_channels, + s3cdma->phy_chans = devm_kcalloc(&pdev->dev, + pdata->num_phy_channels, + sizeof(struct s3c24xx_dma_phy), GFP_KERNEL); if (!s3cdma->phy_chans) return -ENOMEM; diff --git a/drivers/dma/sh/shdma-base.c b/drivers/dma/sh/shdma-base.c index 12fa48e380cf..6b5626e299b2 100644 --- a/drivers/dma/sh/shdma-base.c +++ b/drivers/dma/sh/shdma-base.c @@ -1045,8 +1045,9 @@ EXPORT_SYMBOL(shdma_cleanup); static int __init shdma_enter(void) { - shdma_slave_used = kzalloc(DIV_ROUND_UP(slave_num, BITS_PER_LONG) * - sizeof(long), GFP_KERNEL); + shdma_slave_used = kcalloc(DIV_ROUND_UP(slave_num, BITS_PER_LONG), + sizeof(long), + GFP_KERNEL); if (!shdma_slave_used) return -ENOMEM; return 0; diff --git a/drivers/dma/xilinx/zynqmp_dma.c b/drivers/dma/xilinx/zynqmp_dma.c index f14645817ed8..c74a88b65039 100644 --- a/drivers/dma/xilinx/zynqmp_dma.c +++ b/drivers/dma/xilinx/zynqmp_dma.c @@ -471,7 +471,7 @@ static int zynqmp_dma_alloc_chan_resources(struct dma_chan *dchan) if (ret < 0) return ret; - chan->sw_desc_pool = kzalloc(sizeof(*desc) * ZYNQMP_DMA_NUM_DESCS, + chan->sw_desc_pool = kcalloc(ZYNQMP_DMA_NUM_DESCS, sizeof(*desc), GFP_KERNEL); if (!chan->sw_desc_pool) return -ENOMEM; diff --git a/drivers/dma/zx_dma.c b/drivers/dma/zx_dma.c index 2bb695315300..2571bc7693df 100644 --- a/drivers/dma/zx_dma.c +++ b/drivers/dma/zx_dma.c @@ -798,8 +798,8 @@ static int zx_dma_probe(struct platform_device *op) return -ENOMEM; /* init phy channel */ - d->phy = devm_kzalloc(&op->dev, - d->dma_channels * sizeof(struct zx_dma_phy), GFP_KERNEL); + d->phy = devm_kcalloc(&op->dev, + d->dma_channels, sizeof(struct zx_dma_phy), GFP_KERNEL); if (!d->phy) return -ENOMEM; @@ -834,8 +834,8 @@ static int zx_dma_probe(struct platform_device *op) d->slave.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT; /* init virtual channel */ - d->chans = devm_kzalloc(&op->dev, - d->dma_requests * sizeof(struct zx_dma_chan), GFP_KERNEL); + d->chans = devm_kcalloc(&op->dev, + d->dma_requests, sizeof(struct zx_dma_chan), GFP_KERNEL); if (!d->chans) return -ENOMEM; diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 329cb96f886f..18aeabb1d5ee 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -3451,7 +3451,7 @@ static int __init amd64_edac_init(void) opstate_init(); err = -ENOMEM; - ecc_stngs = kzalloc(amd_nb_num() * sizeof(ecc_stngs[0]), GFP_KERNEL); + ecc_stngs = kcalloc(amd_nb_num(), sizeof(ecc_stngs[0]), GFP_KERNEL); if (!ecc_stngs) goto err_free; diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 4d0ea3563d47..8ed4dd9c571b 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -461,7 +461,7 @@ static struct i7core_dev *alloc_i7core_dev(u8 socket, if (!i7core_dev) return NULL; - i7core_dev->pdev = kzalloc(sizeof(*i7core_dev->pdev) * table->n_devs, + i7core_dev->pdev = kcalloc(table->n_devs, sizeof(*i7core_dev->pdev), GFP_KERNEL); if (!i7core_dev->pdev) { kfree(i7core_dev); diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 8bff5fd18185..af83ad58819c 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -1126,8 +1126,9 @@ int extcon_dev_register(struct extcon_dev *edev) char *str; struct extcon_cable *cable; - edev->cables = kzalloc(sizeof(struct extcon_cable) * - edev->max_supported, GFP_KERNEL); + edev->cables = kcalloc(edev->max_supported, + sizeof(struct extcon_cable), + GFP_KERNEL); if (!edev->cables) { ret = -ENOMEM; goto err_sysfs_alloc; @@ -1136,7 +1137,7 @@ int extcon_dev_register(struct extcon_dev *edev) cable = &edev->cables[index]; snprintf(buf, 10, "cable.%d", index); - str = kzalloc(sizeof(char) * (strlen(buf) + 1), + str = kzalloc(strlen(buf) + 1, GFP_KERNEL); if (!str) { for (index--; index >= 0; index--) { @@ -1177,15 +1178,17 @@ int extcon_dev_register(struct extcon_dev *edev) for (index = 0; edev->mutually_exclusive[index]; index++) ; - edev->attrs_muex = kzalloc(sizeof(struct attribute *) * - (index + 1), GFP_KERNEL); + edev->attrs_muex = kcalloc(index + 1, + sizeof(struct attribute *), + GFP_KERNEL); if (!edev->attrs_muex) { ret = -ENOMEM; goto err_muex; } - edev->d_attrs_muex = kzalloc(sizeof(struct device_attribute) * - index, GFP_KERNEL); + edev->d_attrs_muex = kcalloc(index, + sizeof(struct device_attribute), + GFP_KERNEL); if (!edev->d_attrs_muex) { ret = -ENOMEM; kfree(edev->attrs_muex); @@ -1194,7 +1197,7 @@ int extcon_dev_register(struct extcon_dev *edev) for (index = 0; edev->mutually_exclusive[index]; index++) { sprintf(buf, "0x%x", edev->mutually_exclusive[index]); - name = kzalloc(sizeof(char) * (strlen(buf) + 1), + name = kzalloc(strlen(buf) + 1, GFP_KERNEL); if (!name) { for (index--; index >= 0; index--) { @@ -1220,8 +1223,9 @@ int extcon_dev_register(struct extcon_dev *edev) if (edev->max_supported) { edev->extcon_dev_type.groups = - kzalloc(sizeof(struct attribute_group *) * - (edev->max_supported + 2), GFP_KERNEL); + kcalloc(edev->max_supported + 2, + sizeof(struct attribute_group *), + GFP_KERNEL); if (!edev->extcon_dev_type.groups) { ret = -ENOMEM; goto err_alloc_groups; diff --git a/drivers/firewire/core-iso.c b/drivers/firewire/core-iso.c index 38c0aa60b2cb..051327a951b1 100644 --- a/drivers/firewire/core-iso.c +++ b/drivers/firewire/core-iso.c @@ -45,8 +45,8 @@ int fw_iso_buffer_alloc(struct fw_iso_buffer *buffer, int page_count) buffer->page_count = 0; buffer->page_count_mapped = 0; - buffer->pages = kmalloc(page_count * sizeof(buffer->pages[0]), - GFP_KERNEL); + buffer->pages = kmalloc_array(page_count, sizeof(buffer->pages[0]), + GFP_KERNEL); if (buffer->pages == NULL) return -ENOMEM; diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index 60e75e6d9104..82ba110d9d1a 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c @@ -1121,7 +1121,7 @@ static int fwnet_broadcast_start(struct fwnet_device *dev) max_receive = 1U << (dev->card->max_receive + 1); num_packets = (FWNET_ISO_PAGE_COUNT * PAGE_SIZE) / max_receive; - ptrptr = kmalloc(sizeof(void *) * num_packets, GFP_KERNEL); + ptrptr = kmalloc_array(num_packets, sizeof(void *), GFP_KERNEL); if (!ptrptr) { retval = -ENOMEM; goto failed; diff --git a/drivers/firmware/arm_scmi/base.c b/drivers/firmware/arm_scmi/base.c index 0d3806c0d432..9dff33ea6416 100644 --- a/drivers/firmware/arm_scmi/base.c +++ b/drivers/firmware/arm_scmi/base.c @@ -26,7 +26,7 @@ struct scmi_msg_resp_base_attributes { * scmi_base_attributes_get() - gets the implementation details * that are associated with the base protocol. * - * @handle - SCMI entity handle + * @handle: SCMI entity handle * * Return: 0 on success, else appropriate SCMI error. */ @@ -37,7 +37,7 @@ static int scmi_base_attributes_get(const struct scmi_handle *handle) struct scmi_msg_resp_base_attributes *attr_info; struct scmi_revision_info *rev = handle->version; - ret = scmi_one_xfer_init(handle, PROTOCOL_ATTRIBUTES, + ret = scmi_xfer_get_init(handle, PROTOCOL_ATTRIBUTES, SCMI_PROTOCOL_BASE, 0, sizeof(*attr_info), &t); if (ret) return ret; @@ -49,15 +49,16 @@ static int scmi_base_attributes_get(const struct scmi_handle *handle) rev->num_agents = attr_info->num_agents; } - scmi_one_xfer_put(handle, t); + scmi_xfer_put(handle, t); + return ret; } /** * scmi_base_vendor_id_get() - gets vendor/subvendor identifier ASCII string. * - * @handle - SCMI entity handle - * @sub_vendor - specify true if sub-vendor ID is needed + * @handle: SCMI entity handle + * @sub_vendor: specify true if sub-vendor ID is needed * * Return: 0 on success, else appropriate SCMI error. */ @@ -80,7 +81,7 @@ scmi_base_vendor_id_get(const struct scmi_handle *handle, bool sub_vendor) size = ARRAY_SIZE(rev->vendor_id); } - ret = scmi_one_xfer_init(handle, cmd, SCMI_PROTOCOL_BASE, 0, size, &t); + ret = scmi_xfer_get_init(handle, cmd, SCMI_PROTOCOL_BASE, 0, size, &t); if (ret) return ret; @@ -88,7 +89,8 @@ scmi_base_vendor_id_get(const struct scmi_handle *handle, bool sub_vendor) if (!ret) memcpy(vendor_id, t->rx.buf, size); - scmi_one_xfer_put(handle, t); + scmi_xfer_put(handle, t); + return ret; } @@ -97,7 +99,7 @@ scmi_base_vendor_id_get(const struct scmi_handle *handle, bool sub_vendor) * implementation 32-bit version. The format of the version number is * vendor-specific * - * @handle - SCMI entity handle + * @handle: SCMI entity handle * * Return: 0 on success, else appropriate SCMI error. */ @@ -109,7 +111,7 @@ scmi_base_implementation_version_get(const struct scmi_handle *handle) struct scmi_xfer *t; struct scmi_revision_info *rev = handle->version; - ret = scmi_one_xfer_init(handle, BASE_DISCOVER_IMPLEMENT_VERSION, + ret = scmi_xfer_get_init(handle, BASE_DISCOVER_IMPLEMENT_VERSION, SCMI_PROTOCOL_BASE, 0, sizeof(*impl_ver), &t); if (ret) return ret; @@ -120,7 +122,8 @@ scmi_base_implementation_version_get(const struct scmi_handle *handle) rev->impl_ver = le32_to_cpu(*impl_ver); } - scmi_one_xfer_put(handle, t); + scmi_xfer_put(handle, t); + return ret; } @@ -128,8 +131,8 @@ scmi_base_implementation_version_get(const struct scmi_handle *handle) * scmi_base_implementation_list_get() - gets the list of protocols it is * OSPM is allowed to access * - * @handle - SCMI entity handle - * @protocols_imp - pointer to hold the list of protocol identifiers + * @handle: SCMI entity handle + * @protocols_imp: pointer to hold the list of protocol identifiers * * Return: 0 on success, else appropriate SCMI error. */ @@ -143,7 +146,7 @@ static int scmi_base_implementation_list_get(const struct scmi_handle *handle, u32 tot_num_ret = 0, loop_num_ret; struct device *dev = handle->dev; - ret = scmi_one_xfer_init(handle, BASE_DISCOVER_LIST_PROTOCOLS, + ret = scmi_xfer_get_init(handle, BASE_DISCOVER_LIST_PROTOCOLS, SCMI_PROTOCOL_BASE, sizeof(*num_skip), 0, &t); if (ret) return ret; @@ -172,16 +175,17 @@ static int scmi_base_implementation_list_get(const struct scmi_handle *handle, tot_num_ret += loop_num_ret; } while (loop_num_ret); - scmi_one_xfer_put(handle, t); + scmi_xfer_put(handle, t); + return ret; } /** * scmi_base_discover_agent_get() - discover the name of an agent * - * @handle - SCMI entity handle - * @id - Agent identifier - * @name - Agent identifier ASCII string + * @handle: SCMI entity handle + * @id: Agent identifier + * @name: Agent identifier ASCII string * * An agent id of 0 is reserved to identify the platform itself. * Generally operating system is represented as "OSPM" @@ -194,7 +198,7 @@ static int scmi_base_discover_agent_get(const struct scmi_handle *handle, int ret; struct scmi_xfer *t; - ret = scmi_one_xfer_init(handle, BASE_DISCOVER_AGENT, + ret = scmi_xfer_get_init(handle, BASE_DISCOVER_AGENT, SCMI_PROTOCOL_BASE, sizeof(__le32), SCMI_MAX_STR_SIZE, &t); if (ret) @@ -206,7 +210,8 @@ static int scmi_base_discover_agent_get(const struct scmi_handle *handle, if (!ret) memcpy(name, t->rx.buf, SCMI_MAX_STR_SIZE); - scmi_one_xfer_put(handle, t); + scmi_xfer_put(handle, t); + return ret; } diff --git a/drivers/firmware/arm_scmi/bus.c b/drivers/firmware/arm_scmi/bus.c index f2760a596c28..472c88ae1c0f 100644 --- a/drivers/firmware/arm_scmi/bus.c +++ b/drivers/firmware/arm_scmi/bus.c @@ -125,13 +125,13 @@ scmi_device_create(struct device_node *np, struct device *parent, int protocol) int id, retval; struct scmi_device *scmi_dev; - id = ida_simple_get(&scmi_bus_id, 1, 0, GFP_KERNEL); - if (id < 0) - return NULL; - scmi_dev = kzalloc(sizeof(*scmi_dev), GFP_KERNEL); if (!scmi_dev) - goto no_mem; + return NULL; + + id = ida_simple_get(&scmi_bus_id, 1, 0, GFP_KERNEL); + if (id < 0) + goto free_mem; scmi_dev->id = id; scmi_dev->protocol_id = protocol; @@ -141,13 +141,15 @@ scmi_device_create(struct device_node *np, struct device *parent, int protocol) dev_set_name(&scmi_dev->dev, "scmi_dev.%d", id); retval = device_register(&scmi_dev->dev); - if (!retval) - return scmi_dev; + if (retval) + goto put_dev; + return scmi_dev; +put_dev: put_device(&scmi_dev->dev); - kfree(scmi_dev); -no_mem: ida_simple_remove(&scmi_bus_id, id); +free_mem: + kfree(scmi_dev); return NULL; } @@ -171,9 +173,9 @@ int scmi_protocol_register(int protocol_id, scmi_prot_init_fn_t fn) spin_lock(&protocol_lock); ret = idr_alloc(&scmi_protocols, fn, protocol_id, protocol_id + 1, GFP_ATOMIC); + spin_unlock(&protocol_lock); if (ret != protocol_id) pr_err("unable to allocate SCMI idr slot, err %d\n", ret); - spin_unlock(&protocol_lock); return ret; } diff --git a/drivers/firmware/arm_scmi/clock.c b/drivers/firmware/arm_scmi/clock.c index 2b90606452a2..e4119eb34986 100644 --- a/drivers/firmware/arm_scmi/clock.c +++ b/drivers/firmware/arm_scmi/clock.c @@ -77,7 +77,7 @@ static int scmi_clock_protocol_attributes_get(const struct scmi_handle *handle, struct scmi_xfer *t; struct scmi_msg_resp_clock_protocol_attributes *attr; - ret = scmi_one_xfer_init(handle, PROTOCOL_ATTRIBUTES, + ret = scmi_xfer_get_init(handle, PROTOCOL_ATTRIBUTES, SCMI_PROTOCOL_CLOCK, 0, sizeof(*attr), &t); if (ret) return ret; @@ -90,7 +90,7 @@ static int scmi_clock_protocol_attributes_get(const struct scmi_handle *handle, ci->max_async_req = attr->max_async_req; } - scmi_one_xfer_put(handle, t); + scmi_xfer_put(handle, t); return ret; } @@ -101,7 +101,7 @@ static int scmi_clock_attributes_get(const struct scmi_handle *handle, struct scmi_xfer *t; struct scmi_msg_resp_clock_attributes *attr; - ret = scmi_one_xfer_init(handle, CLOCK_ATTRIBUTES, SCMI_PROTOCOL_CLOCK, + ret = scmi_xfer_get_init(handle, CLOCK_ATTRIBUTES, SCMI_PROTOCOL_CLOCK, sizeof(clk_id), sizeof(*attr), &t); if (ret) return ret; @@ -115,7 +115,7 @@ static int scmi_clock_attributes_get(const struct scmi_handle *handle, else clk->name[0] = '\0'; - scmi_one_xfer_put(handle, t); + scmi_xfer_put(handle, t); return ret; } @@ -132,7 +132,7 @@ scmi_clock_describe_rates_get(const struct scmi_handle *handle, u32 clk_id, struct scmi_msg_clock_describe_rates *clk_desc; struct scmi_msg_resp_clock_describe_rates *rlist; - ret = scmi_one_xfer_init(handle, CLOCK_DESCRIBE_RATES, + ret = scmi_xfer_get_init(handle, CLOCK_DESCRIBE_RATES, SCMI_PROTOCOL_CLOCK, sizeof(*clk_desc), 0, &t); if (ret) return ret; @@ -186,7 +186,7 @@ scmi_clock_describe_rates_get(const struct scmi_handle *handle, u32 clk_id, clk->list.num_rates = tot_rate_cnt; err: - scmi_one_xfer_put(handle, t); + scmi_xfer_put(handle, t); return ret; } @@ -196,7 +196,7 @@ scmi_clock_rate_get(const struct scmi_handle *handle, u32 clk_id, u64 *value) int ret; struct scmi_xfer *t; - ret = scmi_one_xfer_init(handle, CLOCK_RATE_GET, SCMI_PROTOCOL_CLOCK, + ret = scmi_xfer_get_init(handle, CLOCK_RATE_GET, SCMI_PROTOCOL_CLOCK, sizeof(__le32), sizeof(u64), &t); if (ret) return ret; @@ -211,7 +211,7 @@ scmi_clock_rate_get(const struct scmi_handle *handle, u32 clk_id, u64 *value) *value |= (u64)le32_to_cpu(*(pval + 1)) << 32; } - scmi_one_xfer_put(handle, t); + scmi_xfer_put(handle, t); return ret; } @@ -222,7 +222,7 @@ static int scmi_clock_rate_set(const struct scmi_handle *handle, u32 clk_id, struct scmi_xfer *t; struct scmi_clock_set_rate *cfg; - ret = scmi_one_xfer_init(handle, CLOCK_RATE_SET, SCMI_PROTOCOL_CLOCK, + ret = scmi_xfer_get_init(handle, CLOCK_RATE_SET, SCMI_PROTOCOL_CLOCK, sizeof(*cfg), 0, &t); if (ret) return ret; @@ -235,7 +235,7 @@ static int scmi_clock_rate_set(const struct scmi_handle *handle, u32 clk_id, ret = scmi_do_xfer(handle, t); - scmi_one_xfer_put(handle, t); + scmi_xfer_put(handle, t); return ret; } @@ -246,7 +246,7 @@ scmi_clock_config_set(const struct scmi_handle *handle, u32 clk_id, u32 config) struct scmi_xfer *t; struct scmi_clock_set_config *cfg; - ret = scmi_one_xfer_init(handle, CLOCK_CONFIG_SET, SCMI_PROTOCOL_CLOCK, + ret = scmi_xfer_get_init(handle, CLOCK_CONFIG_SET, SCMI_PROTOCOL_CLOCK, sizeof(*cfg), 0, &t); if (ret) return ret; @@ -257,7 +257,7 @@ scmi_clock_config_set(const struct scmi_handle *handle, u32 clk_id, u32 config) ret = scmi_do_xfer(handle, t); - scmi_one_xfer_put(handle, t); + scmi_xfer_put(handle, t); return ret; } diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index 0c30234f9098..937a930ce87d 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -7,6 +7,7 @@ * Copyright (C) 2018 ARM Ltd. */ +#include <linux/bitfield.h> #include <linux/completion.h> #include <linux/device.h> #include <linux/errno.h> @@ -14,10 +15,10 @@ #include <linux/scmi_protocol.h> #include <linux/types.h> -#define PROTOCOL_REV_MINOR_BITS 16 -#define PROTOCOL_REV_MINOR_MASK ((1U << PROTOCOL_REV_MINOR_BITS) - 1) -#define PROTOCOL_REV_MAJOR(x) ((x) >> PROTOCOL_REV_MINOR_BITS) -#define PROTOCOL_REV_MINOR(x) ((x) & PROTOCOL_REV_MINOR_MASK) +#define PROTOCOL_REV_MINOR_MASK GENMASK(15, 0) +#define PROTOCOL_REV_MAJOR_MASK GENMASK(31, 16) +#define PROTOCOL_REV_MAJOR(x) (u16)(FIELD_GET(PROTOCOL_REV_MAJOR_MASK, (x))) +#define PROTOCOL_REV_MINOR(x) (u16)(FIELD_GET(PROTOCOL_REV_MINOR_MASK, (x))) #define MAX_PROTOCOLS_IMP 16 #define MAX_OPPS 16 @@ -50,8 +51,11 @@ struct scmi_msg_resp_prot_version { * @id: The identifier of the command being sent * @protocol_id: The identifier of the protocol used to send @id command * @seq: The token to identify the message. when a message/command returns, - * the platform returns the whole message header unmodified including - * the token. + * the platform returns the whole message header unmodified including + * the token + * @status: Status of the transfer once it's complete + * @poll_completion: Indicate if the transfer needs to be polled for + * completion or interrupt mode is used */ struct scmi_msg_hdr { u8 id; @@ -82,18 +86,16 @@ struct scmi_msg { * buffer for the rx path as we use for the tx path. * @done: completion event */ - struct scmi_xfer { - void *con_priv; struct scmi_msg_hdr hdr; struct scmi_msg tx; struct scmi_msg rx; struct completion done; }; -void scmi_one_xfer_put(const struct scmi_handle *h, struct scmi_xfer *xfer); +void scmi_xfer_put(const struct scmi_handle *h, struct scmi_xfer *xfer); int scmi_do_xfer(const struct scmi_handle *h, struct scmi_xfer *xfer); -int scmi_one_xfer_init(const struct scmi_handle *h, u8 msg_id, u8 prot_id, +int scmi_xfer_get_init(const struct scmi_handle *h, u8 msg_id, u8 prot_id, size_t tx_size, size_t rx_size, struct scmi_xfer **p); int scmi_handle_put(const struct scmi_handle *handle); struct scmi_handle *scmi_handle_get(struct device *dev); diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 2455be8cbc4f..8f952f2f1a29 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -29,16 +29,12 @@ #include "common.h" -#define MSG_ID_SHIFT 0 -#define MSG_ID_MASK 0xff -#define MSG_TYPE_SHIFT 8 -#define MSG_TYPE_MASK 0x3 -#define MSG_PROTOCOL_ID_SHIFT 10 -#define MSG_PROTOCOL_ID_MASK 0xff -#define MSG_TOKEN_ID_SHIFT 18 -#define MSG_TOKEN_ID_MASK 0x3ff -#define MSG_XTRACT_TOKEN(header) \ - (((header) >> MSG_TOKEN_ID_SHIFT) & MSG_TOKEN_ID_MASK) +#define MSG_ID_MASK GENMASK(7, 0) +#define MSG_TYPE_MASK GENMASK(9, 8) +#define MSG_PROTOCOL_ID_MASK GENMASK(17, 10) +#define MSG_TOKEN_ID_MASK GENMASK(27, 18) +#define MSG_XTRACT_TOKEN(hdr) FIELD_GET(MSG_TOKEN_ID_MASK, (hdr)) +#define MSG_TOKEN_MAX (MSG_XTRACT_TOKEN(MSG_TOKEN_ID_MASK) + 1) enum scmi_error_codes { SCMI_SUCCESS = 0, /* Success */ @@ -55,7 +51,7 @@ enum scmi_error_codes { SCMI_ERR_MAX }; -/* List of all SCMI devices active in system */ +/* List of all SCMI devices active in system */ static LIST_HEAD(scmi_list); /* Protection for the entire list */ static DEFINE_MUTEX(scmi_list_mutex); @@ -72,7 +68,6 @@ static DEFINE_MUTEX(scmi_list_mutex); struct scmi_xfers_info { struct scmi_xfer *xfer_block; unsigned long *xfer_alloc_table; - /* protect transfer allocation */ spinlock_t xfer_lock; }; @@ -98,6 +93,7 @@ struct scmi_desc { * @payload: Transmit/Receive mailbox channel payload area * @dev: Reference to device in the SCMI hierarchy corresponding to this * channel + * @handle: Pointer to SCMI entity handle */ struct scmi_chan_info { struct mbox_client cl; @@ -108,7 +104,7 @@ struct scmi_chan_info { }; /** - * struct scmi_info - Structure representing a SCMI instance + * struct scmi_info - Structure representing a SCMI instance * * @dev: Device pointer * @desc: SoC description for this instance @@ -117,9 +113,9 @@ struct scmi_chan_info { * implementation version and (sub-)vendor identification. * @minfo: Message info * @tx_idr: IDR object to map protocol id to channel info pointer - * @protocols_imp: list of protocols implemented, currently maximum of + * @protocols_imp: List of protocols implemented, currently maximum of * MAX_PROTOCOLS_IMP elements allocated by the base protocol - * @node: list head + * @node: List head * @users: Number of users of this instance */ struct scmi_info { @@ -225,9 +221,7 @@ static void scmi_rx_callback(struct mbox_client *cl, void *m) xfer_id = MSG_XTRACT_TOKEN(ioread32(&mem->msg_header)); - /* - * Are we even expecting this? - */ + /* Are we even expecting this? */ if (!test_bit(xfer_id, minfo->xfer_alloc_table)) { dev_err(dev, "message for %d is not expected!\n", xfer_id); return; @@ -252,12 +246,14 @@ static void scmi_rx_callback(struct mbox_client *cl, void *m) * * @hdr: pointer to header containing all the information on message id, * protocol id and sequence id. + * + * Return: 32-bit packed command header to be sent to the platform. */ static inline u32 pack_scmi_header(struct scmi_msg_hdr *hdr) { - return ((hdr->id & MSG_ID_MASK) << MSG_ID_SHIFT) | - ((hdr->seq & MSG_TOKEN_ID_MASK) << MSG_TOKEN_ID_SHIFT) | - ((hdr->protocol_id & MSG_PROTOCOL_ID_MASK) << MSG_PROTOCOL_ID_SHIFT); + return FIELD_PREP(MSG_ID_MASK, hdr->id) | + FIELD_PREP(MSG_TOKEN_ID_MASK, hdr->seq) | + FIELD_PREP(MSG_PROTOCOL_ID_MASK, hdr->protocol_id); } /** @@ -286,9 +282,9 @@ static void scmi_tx_prepare(struct mbox_client *cl, void *m) } /** - * scmi_one_xfer_get() - Allocate one message + * scmi_xfer_get() - Allocate one message * - * @handle: SCMI entity handle + * @handle: Pointer to SCMI entity handle * * Helper function which is used by various command functions that are * exposed to clients of this driver for allocating a message traffic event. @@ -299,7 +295,7 @@ static void scmi_tx_prepare(struct mbox_client *cl, void *m) * * Return: 0 if all went fine, else corresponding error. */ -static struct scmi_xfer *scmi_one_xfer_get(const struct scmi_handle *handle) +static struct scmi_xfer *scmi_xfer_get(const struct scmi_handle *handle) { u16 xfer_id; struct scmi_xfer *xfer; @@ -328,14 +324,14 @@ static struct scmi_xfer *scmi_one_xfer_get(const struct scmi_handle *handle) } /** - * scmi_one_xfer_put() - Release a message + * scmi_xfer_put() - Release a message * - * @minfo: transfer info pointer - * @xfer: message that was reserved by scmi_one_xfer_get + * @handle: Pointer to SCMI entity handle + * @xfer: message that was reserved by scmi_xfer_get * * This holds a spinlock to maintain integrity of internal data structures. */ -void scmi_one_xfer_put(const struct scmi_handle *handle, struct scmi_xfer *xfer) +void scmi_xfer_put(const struct scmi_handle *handle, struct scmi_xfer *xfer) { unsigned long flags; struct scmi_info *info = handle_to_scmi_info(handle); @@ -378,12 +374,12 @@ static bool scmi_xfer_done_no_timeout(const struct scmi_chan_info *cinfo, /** * scmi_do_xfer() - Do one transfer * - * @info: Pointer to SCMI entity information + * @handle: Pointer to SCMI entity handle * @xfer: Transfer to initiate and wait for response * * Return: -ETIMEDOUT in case of no response, if transmit error, - * return corresponding error, else if all goes well, - * return 0. + * return corresponding error, else if all goes well, + * return 0. */ int scmi_do_xfer(const struct scmi_handle *handle, struct scmi_xfer *xfer) { @@ -440,22 +436,22 @@ int scmi_do_xfer(const struct scmi_handle *handle, struct scmi_xfer *xfer) } /** - * scmi_one_xfer_init() - Allocate and initialise one message + * scmi_xfer_get_init() - Allocate and initialise one message * - * @handle: SCMI entity handle + * @handle: Pointer to SCMI entity handle * @msg_id: Message identifier - * @msg_prot_id: Protocol identifier for the message + * @prot_id: Protocol identifier for the message * @tx_size: transmit message size * @rx_size: receive message size * @p: pointer to the allocated and initialised message * - * This function allocates the message using @scmi_one_xfer_get and + * This function allocates the message using @scmi_xfer_get and * initialise the header. * * Return: 0 if all went fine with @p pointing to message, else * corresponding error. */ -int scmi_one_xfer_init(const struct scmi_handle *handle, u8 msg_id, u8 prot_id, +int scmi_xfer_get_init(const struct scmi_handle *handle, u8 msg_id, u8 prot_id, size_t tx_size, size_t rx_size, struct scmi_xfer **p) { int ret; @@ -468,7 +464,7 @@ int scmi_one_xfer_init(const struct scmi_handle *handle, u8 msg_id, u8 prot_id, tx_size > info->desc->max_msg_size) return -ERANGE; - xfer = scmi_one_xfer_get(handle); + xfer = scmi_xfer_get(handle); if (IS_ERR(xfer)) { ret = PTR_ERR(xfer); dev_err(dev, "failed to get free message slot(%d)\n", ret); @@ -482,13 +478,16 @@ int scmi_one_xfer_init(const struct scmi_handle *handle, u8 msg_id, u8 prot_id, xfer->hdr.poll_completion = false; *p = xfer; + return 0; } /** * scmi_version_get() - command to get the revision of the SCMI entity * - * @handle: Handle to SCMI entity information + * @handle: Pointer to SCMI entity handle + * @protocol: Protocol identifier for the message + * @version: Holds returned version of protocol. * * Updates the SCMI information in the internal data structure. * @@ -501,7 +500,7 @@ int scmi_version_get(const struct scmi_handle *handle, u8 protocol, __le32 *rev_info; struct scmi_xfer *t; - ret = scmi_one_xfer_init(handle, PROTOCOL_VERSION, protocol, 0, + ret = scmi_xfer_get_init(handle, PROTOCOL_VERSION, protocol, 0, sizeof(*version), &t); if (ret) return ret; @@ -512,7 +511,7 @@ int scmi_version_get(const struct scmi_handle *handle, u8 protocol, *version = le32_to_cpu(*rev_info); } - scmi_one_xfer_put(handle, t); + scmi_xfer_put(handle, t); return ret; } @@ -540,12 +539,12 @@ scmi_is_protocol_implemented(const struct scmi_handle *handle, u8 prot_id) } /** - * scmi_handle_get() - Get the SCMI handle for a device + * scmi_handle_get() - Get the SCMI handle for a device * * @dev: pointer to device for which we want SCMI handle * * NOTE: The function does not track individual clients of the framework - * and is expected to be maintained by caller of SCMI protocol library. + * and is expected to be maintained by caller of SCMI protocol library. * scmi_handle_put must be balanced with successful scmi_handle_get * * Return: pointer to handle if successful, NULL on error @@ -576,7 +575,7 @@ struct scmi_handle *scmi_handle_get(struct device *dev) * @handle: handle acquired by scmi_handle_get * * NOTE: The function does not track individual clients of the framework - * and is expected to be maintained by caller of SCMI protocol library. + * and is expected to be maintained by caller of SCMI protocol library. * scmi_handle_put must be balanced with successful scmi_handle_get * * Return: 0 is successfully released @@ -599,7 +598,7 @@ int scmi_handle_put(const struct scmi_handle *handle) } static const struct scmi_desc scmi_generic_desc = { - .max_rx_timeout_ms = 30, /* we may increase this if required */ + .max_rx_timeout_ms = 30, /* We may increase this if required */ .max_msg = 20, /* Limited by MBOX_TX_QUEUE_LEN */ .max_msg_size = 128, }; @@ -621,9 +620,9 @@ static int scmi_xfer_info_init(struct scmi_info *sinfo) struct scmi_xfers_info *info = &sinfo->minfo; /* Pre-allocated messages, no more than what hdr.seq can support */ - if (WARN_ON(desc->max_msg >= (MSG_TOKEN_ID_MASK + 1))) { - dev_err(dev, "Maximum message of %d exceeds supported %d\n", - desc->max_msg, MSG_TOKEN_ID_MASK + 1); + if (WARN_ON(desc->max_msg >= MSG_TOKEN_MAX)) { + dev_err(dev, "Maximum message of %d exceeds supported %ld\n", + desc->max_msg, MSG_TOKEN_MAX); return -EINVAL; } @@ -637,8 +636,6 @@ static int scmi_xfer_info_init(struct scmi_info *sinfo) if (!info->xfer_alloc_table) return -ENOMEM; - bitmap_zero(info->xfer_alloc_table, desc->max_msg); - /* Pre-initialize the buffer pointer to pre-allocated buffers */ for (i = 0, xfer = info->xfer_block; i < desc->max_msg; i++, xfer++) { xfer->rx.buf = devm_kcalloc(dev, sizeof(u8), desc->max_msg_size, @@ -690,11 +687,12 @@ static int scmi_remove(struct platform_device *pdev) list_del(&info->node); mutex_unlock(&scmi_list_mutex); - if (!ret) { - /* Safe to free channels since no more users */ - ret = idr_for_each(idr, scmi_mbox_free_channel, idr); - idr_destroy(&info->tx_idr); - } + if (ret) + return ret; + + /* Safe to free channels since no more users */ + ret = idr_for_each(idr, scmi_mbox_free_channel, idr); + idr_destroy(&info->tx_idr); return ret; } @@ -841,7 +839,8 @@ static int scmi_probe(struct platform_device *pdev) if (of_property_read_u32(child, "reg", &prot_id)) continue; - prot_id &= MSG_PROTOCOL_ID_MASK; + if (!FIELD_FIT(MSG_PROTOCOL_ID_MASK, prot_id)) + dev_err(dev, "Out of range protocol %d\n", prot_id); if (!scmi_is_protocol_implemented(handle, prot_id)) { dev_err(dev, "SCMI protocol %d not implemented\n", diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c index 987c64d19801..2a219b1261b1 100644 --- a/drivers/firmware/arm_scmi/perf.c +++ b/drivers/firmware/arm_scmi/perf.c @@ -115,7 +115,7 @@ static int scmi_perf_attributes_get(const struct scmi_handle *handle, struct scmi_xfer *t; struct scmi_msg_resp_perf_attributes *attr; - ret = scmi_one_xfer_init(handle, PROTOCOL_ATTRIBUTES, + ret = scmi_xfer_get_init(handle, PROTOCOL_ATTRIBUTES, SCMI_PROTOCOL_PERF, 0, sizeof(*attr), &t); if (ret) return ret; @@ -133,7 +133,7 @@ static int scmi_perf_attributes_get(const struct scmi_handle *handle, pi->stats_size = le32_to_cpu(attr->stats_size); } - scmi_one_xfer_put(handle, t); + scmi_xfer_put(handle, t); return ret; } @@ -145,7 +145,7 @@ scmi_perf_domain_attributes_get(const struct scmi_handle *handle, u32 domain, struct scmi_xfer *t; struct scmi_msg_resp_perf_domain_attributes *attr; - ret = scmi_one_xfer_init(handle, PERF_DOMAIN_ATTRIBUTES, + ret = scmi_xfer_get_init(handle, PERF_DOMAIN_ATTRIBUTES, SCMI_PROTOCOL_PERF, sizeof(domain), sizeof(*attr), &t); if (ret) @@ -171,7 +171,7 @@ scmi_perf_domain_attributes_get(const struct scmi_handle *handle, u32 domain, memcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE); } - scmi_one_xfer_put(handle, t); + scmi_xfer_put(handle, t); return ret; } @@ -194,7 +194,7 @@ scmi_perf_describe_levels_get(const struct scmi_handle *handle, u32 domain, struct scmi_msg_perf_describe_levels *dom_info; struct scmi_msg_resp_perf_describe_levels *level_info; - ret = scmi_one_xfer_init(handle, PERF_DESCRIBE_LEVELS, + ret = scmi_xfer_get_init(handle, PERF_DESCRIBE_LEVELS, SCMI_PROTOCOL_PERF, sizeof(*dom_info), 0, &t); if (ret) return ret; @@ -237,7 +237,7 @@ scmi_perf_describe_levels_get(const struct scmi_handle *handle, u32 domain, } while (num_returned && num_remaining); perf_dom->opp_count = tot_opp_cnt; - scmi_one_xfer_put(handle, t); + scmi_xfer_put(handle, t); sort(perf_dom->opp, tot_opp_cnt, sizeof(*opp), opp_cmp_func, NULL); return ret; @@ -250,7 +250,7 @@ static int scmi_perf_limits_set(const struct scmi_handle *handle, u32 domain, struct scmi_xfer *t; struct scmi_perf_set_limits *limits; - ret = scmi_one_xfer_init(handle, PERF_LIMITS_SET, SCMI_PROTOCOL_PERF, + ret = scmi_xfer_get_init(handle, PERF_LIMITS_SET, SCMI_PROTOCOL_PERF, sizeof(*limits), 0, &t); if (ret) return ret; @@ -262,7 +262,7 @@ static int scmi_perf_limits_set(const struct scmi_handle *handle, u32 domain, ret = scmi_do_xfer(handle, t); - scmi_one_xfer_put(handle, t); + scmi_xfer_put(handle, t); return ret; } @@ -273,7 +273,7 @@ static int scmi_perf_limits_get(const struct scmi_handle *handle, u32 domain, struct scmi_xfer *t; struct scmi_perf_get_limits *limits; - ret = scmi_one_xfer_init(handle, PERF_LIMITS_GET, SCMI_PROTOCOL_PERF, + ret = scmi_xfer_get_init(handle, PERF_LIMITS_GET, SCMI_PROTOCOL_PERF, sizeof(__le32), 0, &t); if (ret) return ret; @@ -288,7 +288,7 @@ static int scmi_perf_limits_get(const struct scmi_handle *handle, u32 domain, *min_perf = le32_to_cpu(limits->min_level); } - scmi_one_xfer_put(handle, t); + scmi_xfer_put(handle, t); return ret; } @@ -299,7 +299,7 @@ static int scmi_perf_level_set(const struct scmi_handle *handle, u32 domain, struct scmi_xfer *t; struct scmi_perf_set_level *lvl; - ret = scmi_one_xfer_init(handle, PERF_LEVEL_SET, SCMI_PROTOCOL_PERF, + ret = scmi_xfer_get_init(handle, PERF_LEVEL_SET, SCMI_PROTOCOL_PERF, sizeof(*lvl), 0, &t); if (ret) return ret; @@ -311,7 +311,7 @@ static int scmi_perf_level_set(const struct scmi_handle *handle, u32 domain, ret = scmi_do_xfer(handle, t); - scmi_one_xfer_put(handle, t); + scmi_xfer_put(handle, t); return ret; } @@ -321,7 +321,7 @@ static int scmi_perf_level_get(const struct scmi_handle *handle, u32 domain, int ret; struct scmi_xfer *t; - ret = scmi_one_xfer_init(handle, PERF_LEVEL_GET, SCMI_PROTOCOL_PERF, + ret = scmi_xfer_get_init(handle, PERF_LEVEL_GET, SCMI_PROTOCOL_PERF, sizeof(u32), sizeof(u32), &t); if (ret) return ret; @@ -333,7 +333,7 @@ static int scmi_perf_level_get(const struct scmi_handle *handle, u32 domain, if (!ret) *level = le32_to_cpu(*(__le32 *)t->rx.buf); - scmi_one_xfer_put(handle, t); + scmi_xfer_put(handle, t); return ret; } @@ -349,8 +349,8 @@ static int scmi_dev_domain_id(struct device *dev) return clkspec.args[0]; } -static int scmi_dvfs_add_opps_to_device(const struct scmi_handle *handle, - struct device *dev) +static int scmi_dvfs_device_opps_add(const struct scmi_handle *handle, + struct device *dev) { int idx, ret, domain; unsigned long freq; @@ -383,7 +383,7 @@ static int scmi_dvfs_add_opps_to_device(const struct scmi_handle *handle, return 0; } -static int scmi_dvfs_get_transition_latency(const struct scmi_handle *handle, +static int scmi_dvfs_transition_latency_get(const struct scmi_handle *handle, struct device *dev) { struct perf_dom_info *dom; @@ -432,8 +432,8 @@ static struct scmi_perf_ops perf_ops = { .level_set = scmi_perf_level_set, .level_get = scmi_perf_level_get, .device_domain_id = scmi_dev_domain_id, - .get_transition_latency = scmi_dvfs_get_transition_latency, - .add_opps_to_device = scmi_dvfs_add_opps_to_device, + .transition_latency_get = scmi_dvfs_transition_latency_get, + .device_opps_add = scmi_dvfs_device_opps_add, .freq_set = scmi_dvfs_freq_set, .freq_get = scmi_dvfs_freq_get, }; diff --git a/drivers/firmware/arm_scmi/power.c b/drivers/firmware/arm_scmi/power.c index 087c2876cdf2..cfa033b05aed 100644 --- a/drivers/firmware/arm_scmi/power.c +++ b/drivers/firmware/arm_scmi/power.c @@ -63,7 +63,7 @@ static int scmi_power_attributes_get(const struct scmi_handle *handle, struct scmi_xfer *t; struct scmi_msg_resp_power_attributes *attr; - ret = scmi_one_xfer_init(handle, PROTOCOL_ATTRIBUTES, + ret = scmi_xfer_get_init(handle, PROTOCOL_ATTRIBUTES, SCMI_PROTOCOL_POWER, 0, sizeof(*attr), &t); if (ret) return ret; @@ -78,7 +78,7 @@ static int scmi_power_attributes_get(const struct scmi_handle *handle, pi->stats_size = le32_to_cpu(attr->stats_size); } - scmi_one_xfer_put(handle, t); + scmi_xfer_put(handle, t); return ret; } @@ -90,7 +90,7 @@ scmi_power_domain_attributes_get(const struct scmi_handle *handle, u32 domain, struct scmi_xfer *t; struct scmi_msg_resp_power_domain_attributes *attr; - ret = scmi_one_xfer_init(handle, POWER_DOMAIN_ATTRIBUTES, + ret = scmi_xfer_get_init(handle, POWER_DOMAIN_ATTRIBUTES, SCMI_PROTOCOL_POWER, sizeof(domain), sizeof(*attr), &t); if (ret) @@ -109,7 +109,7 @@ scmi_power_domain_attributes_get(const struct scmi_handle *handle, u32 domain, memcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE); } - scmi_one_xfer_put(handle, t); + scmi_xfer_put(handle, t); return ret; } @@ -120,7 +120,7 @@ scmi_power_state_set(const struct scmi_handle *handle, u32 domain, u32 state) struct scmi_xfer *t; struct scmi_power_set_state *st; - ret = scmi_one_xfer_init(handle, POWER_STATE_SET, SCMI_PROTOCOL_POWER, + ret = scmi_xfer_get_init(handle, POWER_STATE_SET, SCMI_PROTOCOL_POWER, sizeof(*st), 0, &t); if (ret) return ret; @@ -132,7 +132,7 @@ scmi_power_state_set(const struct scmi_handle *handle, u32 domain, u32 state) ret = scmi_do_xfer(handle, t); - scmi_one_xfer_put(handle, t); + scmi_xfer_put(handle, t); return ret; } @@ -142,7 +142,7 @@ scmi_power_state_get(const struct scmi_handle *handle, u32 domain, u32 *state) int ret; struct scmi_xfer *t; - ret = scmi_one_xfer_init(handle, POWER_STATE_GET, SCMI_PROTOCOL_POWER, + ret = scmi_xfer_get_init(handle, POWER_STATE_GET, SCMI_PROTOCOL_POWER, sizeof(u32), sizeof(u32), &t); if (ret) return ret; @@ -153,7 +153,7 @@ scmi_power_state_get(const struct scmi_handle *handle, u32 domain, u32 *state) if (!ret) *state = le32_to_cpu(*(__le32 *)t->rx.buf); - scmi_one_xfer_put(handle, t); + scmi_xfer_put(handle, t); return ret; } diff --git a/drivers/firmware/arm_scmi/sensors.c b/drivers/firmware/arm_scmi/sensors.c index bbb469fea0ed..27f2092b9882 100644 --- a/drivers/firmware/arm_scmi/sensors.c +++ b/drivers/firmware/arm_scmi/sensors.c @@ -79,7 +79,7 @@ static int scmi_sensor_attributes_get(const struct scmi_handle *handle, struct scmi_xfer *t; struct scmi_msg_resp_sensor_attributes *attr; - ret = scmi_one_xfer_init(handle, PROTOCOL_ATTRIBUTES, + ret = scmi_xfer_get_init(handle, PROTOCOL_ATTRIBUTES, SCMI_PROTOCOL_SENSOR, 0, sizeof(*attr), &t); if (ret) return ret; @@ -95,7 +95,7 @@ static int scmi_sensor_attributes_get(const struct scmi_handle *handle, si->reg_size = le32_to_cpu(attr->reg_size); } - scmi_one_xfer_put(handle, t); + scmi_xfer_put(handle, t); return ret; } @@ -108,7 +108,7 @@ static int scmi_sensor_description_get(const struct scmi_handle *handle, struct scmi_xfer *t; struct scmi_msg_resp_sensor_description *buf; - ret = scmi_one_xfer_init(handle, SENSOR_DESCRIPTION_GET, + ret = scmi_xfer_get_init(handle, SENSOR_DESCRIPTION_GET, SCMI_PROTOCOL_SENSOR, sizeof(__le32), 0, &t); if (ret) return ret; @@ -150,7 +150,7 @@ static int scmi_sensor_description_get(const struct scmi_handle *handle, */ } while (num_returned && num_remaining); - scmi_one_xfer_put(handle, t); + scmi_xfer_put(handle, t); return ret; } @@ -162,7 +162,7 @@ scmi_sensor_configuration_set(const struct scmi_handle *handle, u32 sensor_id) struct scmi_xfer *t; struct scmi_msg_set_sensor_config *cfg; - ret = scmi_one_xfer_init(handle, SENSOR_CONFIG_SET, + ret = scmi_xfer_get_init(handle, SENSOR_CONFIG_SET, SCMI_PROTOCOL_SENSOR, sizeof(*cfg), 0, &t); if (ret) return ret; @@ -173,7 +173,7 @@ scmi_sensor_configuration_set(const struct scmi_handle *handle, u32 sensor_id) ret = scmi_do_xfer(handle, t); - scmi_one_xfer_put(handle, t); + scmi_xfer_put(handle, t); return ret; } @@ -185,7 +185,7 @@ static int scmi_sensor_trip_point_set(const struct scmi_handle *handle, struct scmi_xfer *t; struct scmi_msg_set_sensor_trip_point *trip; - ret = scmi_one_xfer_init(handle, SENSOR_TRIP_POINT_SET, + ret = scmi_xfer_get_init(handle, SENSOR_TRIP_POINT_SET, SCMI_PROTOCOL_SENSOR, sizeof(*trip), 0, &t); if (ret) return ret; @@ -198,7 +198,7 @@ static int scmi_sensor_trip_point_set(const struct scmi_handle *handle, ret = scmi_do_xfer(handle, t); - scmi_one_xfer_put(handle, t); + scmi_xfer_put(handle, t); return ret; } @@ -209,7 +209,7 @@ static int scmi_sensor_reading_get(const struct scmi_handle *handle, struct scmi_xfer *t; struct scmi_msg_sensor_reading_get *sensor; - ret = scmi_one_xfer_init(handle, SENSOR_READING_GET, + ret = scmi_xfer_get_init(handle, SENSOR_READING_GET, SCMI_PROTOCOL_SENSOR, sizeof(*sensor), sizeof(u64), &t); if (ret) @@ -227,7 +227,7 @@ static int scmi_sensor_reading_get(const struct scmi_handle *handle, *value |= (u64)le32_to_cpu(*(pval + 1)) << 32; } - scmi_one_xfer_put(handle, t); + scmi_xfer_put(handle, t); return ret; } diff --git a/drivers/firmware/arm_scpi.c b/drivers/firmware/arm_scpi.c index 6d7a6c0a5e07..c7d06a36b23a 100644 --- a/drivers/firmware/arm_scpi.c +++ b/drivers/firmware/arm_scpi.c @@ -890,7 +890,7 @@ static int scpi_alloc_xfer_list(struct device *dev, struct scpi_chan *ch) int i; struct scpi_xfer *xfers; - xfers = devm_kzalloc(dev, MAX_SCPI_XFERS * sizeof(*xfers), GFP_KERNEL); + xfers = devm_kcalloc(dev, MAX_SCPI_XFERS, sizeof(*xfers), GFP_KERNEL); if (!xfers) return -ENOMEM; diff --git a/drivers/firmware/broadcom/bcm47xx_nvram.c b/drivers/firmware/broadcom/bcm47xx_nvram.c index 0b631e5b5b84..d25f080fcb0d 100644 --- a/drivers/firmware/broadcom/bcm47xx_nvram.c +++ b/drivers/firmware/broadcom/bcm47xx_nvram.c @@ -36,7 +36,7 @@ struct nvram_header { static char nvram_buf[NVRAM_SPACE]; static size_t nvram_len; -static const u32 nvram_sizes[] = {0x8000, 0xF000, 0x10000}; +static const u32 nvram_sizes[] = {0x6000, 0x8000, 0xF000, 0x10000}; static u32 find_nvram_size(void __iomem *end) { diff --git a/drivers/firmware/dell_rbu.c b/drivers/firmware/dell_rbu.c index 2f452f1f7c8a..fb8af5cb7c9b 100644 --- a/drivers/firmware/dell_rbu.c +++ b/drivers/firmware/dell_rbu.c @@ -146,7 +146,7 @@ static int create_packet(void *data, size_t length) packet_array_size = max( (unsigned int)(allocation_floor / rbu_data.packetsize), (unsigned int)1); - invalid_addr_packet_array = kzalloc(packet_array_size * sizeof(void*), + invalid_addr_packet_array = kcalloc(packet_array_size, sizeof(void *), GFP_KERNEL); if (!invalid_addr_packet_array) { diff --git a/drivers/firmware/efi/arm-init.c b/drivers/firmware/efi/arm-init.c index 80d1a885def5..b5214c143fee 100644 --- a/drivers/firmware/efi/arm-init.c +++ b/drivers/firmware/efi/arm-init.c @@ -193,7 +193,7 @@ static __init void reserve_regions(void) * uses its own memory map instead. */ memblock_dump_all(); - memblock_remove(0, (phys_addr_t)ULLONG_MAX); + memblock_remove(0, PHYS_ADDR_MAX); for_each_efi_memory_desc(md) { paddr = md->phys_addr; diff --git a/drivers/firmware/efi/capsule.c b/drivers/firmware/efi/capsule.c index 901b9306bf94..4938c29b7c5d 100644 --- a/drivers/firmware/efi/capsule.c +++ b/drivers/firmware/efi/capsule.c @@ -231,7 +231,7 @@ int efi_capsule_update(efi_capsule_header_t *capsule, phys_addr_t *pages) count = DIV_ROUND_UP(imagesize, PAGE_SIZE); sg_count = sg_pages_num(count); - sg_pages = kzalloc(sg_count * sizeof(*sg_pages), GFP_KERNEL); + sg_pages = kcalloc(sg_count, sizeof(*sg_pages), GFP_KERNEL); if (!sg_pages) return -ENOMEM; diff --git a/drivers/firmware/efi/efi-pstore.c b/drivers/firmware/efi/efi-pstore.c index 5a0fa939d70f..cfe87b465819 100644 --- a/drivers/firmware/efi/efi-pstore.c +++ b/drivers/firmware/efi/efi-pstore.c @@ -28,10 +28,9 @@ static int efi_pstore_close(struct pstore_info *psi) return 0; } -static inline u64 generic_id(unsigned long timestamp, - unsigned int part, int count) +static inline u64 generic_id(u64 timestamp, unsigned int part, int count) { - return ((u64) timestamp * 100 + part) * 1000 + count; + return (timestamp * 100 + part) * 1000 + count; } static int efi_pstore_read_func(struct efivar_entry *entry, @@ -42,7 +41,8 @@ static int efi_pstore_read_func(struct efivar_entry *entry, int i; int cnt; unsigned int part; - unsigned long time, size; + unsigned long size; + u64 time; if (efi_guidcmp(entry->var.VendorGuid, vendor)) return 0; @@ -50,7 +50,7 @@ static int efi_pstore_read_func(struct efivar_entry *entry, for (i = 0; i < DUMP_NAME_LEN; i++) name[i] = entry->var.VariableName[i]; - if (sscanf(name, "dump-type%u-%u-%d-%lu-%c", + if (sscanf(name, "dump-type%u-%u-%d-%llu-%c", &record->type, &part, &cnt, &time, &data_type) == 5) { record->id = generic_id(time, part, cnt); record->part = part; @@ -62,7 +62,7 @@ static int efi_pstore_read_func(struct efivar_entry *entry, else record->compressed = false; record->ecc_notice_size = 0; - } else if (sscanf(name, "dump-type%u-%u-%d-%lu", + } else if (sscanf(name, "dump-type%u-%u-%d-%llu", &record->type, &part, &cnt, &time) == 4) { record->id = generic_id(time, part, cnt); record->part = part; @@ -71,7 +71,7 @@ static int efi_pstore_read_func(struct efivar_entry *entry, record->time.tv_nsec = 0; record->compressed = false; record->ecc_notice_size = 0; - } else if (sscanf(name, "dump-type%u-%u-%lu", + } else if (sscanf(name, "dump-type%u-%u-%llu", &record->type, &part, &time) == 3) { /* * Check if an old format, @@ -250,9 +250,10 @@ static int efi_pstore_write(struct pstore_record *record) /* Since we copy the entire length of name, make sure it is wiped. */ memset(name, 0, sizeof(name)); - snprintf(name, sizeof(name), "dump-type%u-%u-%d-%lu-%c", + snprintf(name, sizeof(name), "dump-type%u-%u-%d-%lld-%c", record->type, record->part, record->count, - record->time.tv_sec, record->compressed ? 'C' : 'D'); + (long long)record->time.tv_sec, + record->compressed ? 'C' : 'D'); for (i = 0; i < DUMP_NAME_LEN; i++) efi_name[i] = name[i]; @@ -327,15 +328,15 @@ static int efi_pstore_erase(struct pstore_record *record) char name[DUMP_NAME_LEN]; int ret; - snprintf(name, sizeof(name), "dump-type%u-%u-%d-%lu", + snprintf(name, sizeof(name), "dump-type%u-%u-%d-%lld", record->type, record->part, record->count, - record->time.tv_sec); + (long long)record->time.tv_sec); ret = efi_pstore_erase_name(name); if (ret != -ENOENT) return ret; - snprintf(name, sizeof(name), "dump-type%u-%u-%lu", - record->type, record->part, record->time.tv_sec); + snprintf(name, sizeof(name), "dump-type%u-%u-%lld", + record->type, record->part, (long long)record->time.tv_sec); ret = efi_pstore_erase_name(name); return ret; diff --git a/drivers/firmware/efi/runtime-map.c b/drivers/firmware/efi/runtime-map.c index f377609ff141..84a11d0a8023 100644 --- a/drivers/firmware/efi/runtime-map.c +++ b/drivers/firmware/efi/runtime-map.c @@ -166,7 +166,7 @@ int __init efi_runtime_map_init(struct kobject *efi_kobj) if (!efi_enabled(EFI_MEMMAP)) return 0; - map_entries = kzalloc(efi.memmap.nr_map * sizeof(entry), GFP_KERNEL); + map_entries = kcalloc(efi.memmap.nr_map, sizeof(entry), GFP_KERNEL); if (!map_entries) { ret = -ENOMEM; goto out; diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index 5a7d693009ef..e778af766fae 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -603,6 +603,9 @@ static const struct of_device_id qcom_scm_dt_match[] = { { .compatible = "qcom,scm-msm8996", .data = NULL, /* no clocks */ }, + { .compatible = "qcom,scm-ipq4019", + .data = NULL, /* no clocks */ + }, { .compatible = "qcom,scm", .data = (void *)(SCM_HAS_CORE_CLK | SCM_HAS_IFACE_CLK diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c index 5229036dcfbf..7fa744793bc5 100644 --- a/drivers/firmware/ti_sci.c +++ b/drivers/firmware/ti_sci.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Texas Instruments System Control Interface Protocol Driver * * Copyright (C) 2015-2016 Texas Instruments Incorporated - http://www.ti.com/ * Nishanth Menon - * - * 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. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #define pr_fmt(fmt) "%s: " fmt, __func__ @@ -1862,9 +1854,9 @@ static int ti_sci_probe(struct platform_device *pdev) if (!minfo->xfer_block) return -ENOMEM; - minfo->xfer_alloc_table = devm_kzalloc(dev, - BITS_TO_LONGS(desc->max_msgs) - * sizeof(unsigned long), + minfo->xfer_alloc_table = devm_kcalloc(dev, + BITS_TO_LONGS(desc->max_msgs), + sizeof(unsigned long), GFP_KERNEL); if (!minfo->xfer_alloc_table) return -ENOMEM; diff --git a/drivers/firmware/ti_sci.h b/drivers/firmware/ti_sci.h index 9b611e9e6f6d..12bf316b68df 100644 --- a/drivers/firmware/ti_sci.h +++ b/drivers/firmware/ti_sci.h @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: BSD-3-Clause /* * Texas Instruments System Control Interface (TISCI) Protocol * @@ -6,35 +7,6 @@ * See: http://processors.wiki.ti.com/index.php/TISCI for details * * Copyright (C) 2015-2016 Texas Instruments Incorporated - http://www.ti.com/ - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the - * distribution. - * - * Neither the name of Texas Instruments Incorporated nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * */ #ifndef __TI_SCI_H diff --git a/drivers/fmc/fmc-sdb.c b/drivers/fmc/fmc-sdb.c index ffdc1762b580..d0e65b86dc22 100644 --- a/drivers/fmc/fmc-sdb.c +++ b/drivers/fmc/fmc-sdb.c @@ -48,8 +48,8 @@ static struct sdb_array *__fmc_scan_sdb_tree(struct fmc_device *fmc, arr = kzalloc(sizeof(*arr), GFP_KERNEL); if (!arr) return ERR_PTR(-ENOMEM); - arr->record = kzalloc(sizeof(arr->record[0]) * n, GFP_KERNEL); - arr->subtree = kzalloc(sizeof(arr->subtree[0]) * n, GFP_KERNEL); + arr->record = kcalloc(n, sizeof(arr->record[0]), GFP_KERNEL); + arr->subtree = kcalloc(n, sizeof(arr->subtree[0]), GFP_KERNEL); if (!arr->record || !arr->subtree) { kfree(arr->record); kfree(arr->subtree); diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c index 44c09904daa6..91b90c0cea73 100644 --- a/drivers/gpio/gpio-adnp.c +++ b/drivers/gpio/gpio-adnp.c @@ -427,7 +427,7 @@ static int adnp_irq_setup(struct adnp *adnp) * is chosen to match the register layout of the hardware in that * each segment contains the corresponding bits for all interrupts. */ - adnp->irq_enable = devm_kzalloc(chip->parent, num_regs * 6, + adnp->irq_enable = devm_kcalloc(chip->parent, num_regs, 6, GFP_KERNEL); if (!adnp->irq_enable) return -ENOMEM; diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c index 5e89f1c74a33..b31ae16170e7 100644 --- a/drivers/gpio/gpio-aspeed.c +++ b/drivers/gpio/gpio-aspeed.c @@ -897,8 +897,8 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev) /* Allocate a cache of the output registers */ banks = gpio->config->nr_gpios >> 5; - gpio->dcache = devm_kzalloc(&pdev->dev, - sizeof(u32) * banks, GFP_KERNEL); + gpio->dcache = devm_kcalloc(&pdev->dev, + banks, sizeof(u32), GFP_KERNEL); if (!gpio->dcache) return -ENOMEM; diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c index eb8369b21e90..00272fa7cc4f 100644 --- a/drivers/gpio/gpio-bcm-kona.c +++ b/drivers/gpio/gpio-bcm-kona.c @@ -601,9 +601,10 @@ static int bcm_kona_gpio_probe(struct platform_device *pdev) GPIO_MAX_BANK_NUM); return -ENXIO; } - kona_gpio->banks = devm_kzalloc(dev, - kona_gpio->num_bank * - sizeof(*kona_gpio->banks), GFP_KERNEL); + kona_gpio->banks = devm_kcalloc(dev, + kona_gpio->num_bank, + sizeof(*kona_gpio->banks), + GFP_KERNEL); if (!kona_gpio->banks) return -ENOMEM; diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index b574ecff7761..035a454eca43 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -198,8 +198,8 @@ static int davinci_gpio_probe(struct platform_device *pdev) ngpio = ARCH_NR_GPIOS; nbank = DIV_ROUND_UP(ngpio, 32); - chips = devm_kzalloc(dev, - nbank * sizeof(struct davinci_gpio_controller), + chips = devm_kcalloc(dev, + nbank, sizeof(struct davinci_gpio_controller), GFP_KERNEL); if (!chips) return -ENOMEM; diff --git a/drivers/gpio/gpio-htc-egpio.c b/drivers/gpio/gpio-htc-egpio.c index 516383934945..ad6e5b518669 100644 --- a/drivers/gpio/gpio-htc-egpio.c +++ b/drivers/gpio/gpio-htc-egpio.c @@ -321,8 +321,8 @@ static int __init egpio_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ei); ei->nchips = pdata->num_chips; - ei->chip = devm_kzalloc(&pdev->dev, - sizeof(struct egpio_chip) * ei->nchips, + ei->chip = devm_kcalloc(&pdev->dev, + ei->nchips, sizeof(struct egpio_chip), GFP_KERNEL); if (!ei->chip) { ret = -ENOMEM; diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c index e2bee27eb526..b23d9a36be1f 100644 --- a/drivers/gpio/gpio-ml-ioh.c +++ b/drivers/gpio/gpio-ml-ioh.c @@ -443,7 +443,7 @@ static int ioh_gpio_probe(struct pci_dev *pdev, goto err_iomap; } - chip_save = kzalloc(sizeof(*chip) * 8, GFP_KERNEL); + chip_save = kcalloc(8, sizeof(*chip), GFP_KERNEL); if (chip_save == NULL) { ret = -ENOMEM; goto err_kzalloc; diff --git a/drivers/gpio/gpio-thunderx.c b/drivers/gpio/gpio-thunderx.c index d16e9d4a129b..1306722faa5a 100644 --- a/drivers/gpio/gpio-thunderx.c +++ b/drivers/gpio/gpio-thunderx.c @@ -504,16 +504,17 @@ static int thunderx_gpio_probe(struct pci_dev *pdev, txgpio->base_msi = (c >> 8) & 0xff; } - txgpio->msix_entries = devm_kzalloc(dev, - sizeof(struct msix_entry) * ngpio, + txgpio->msix_entries = devm_kcalloc(dev, + ngpio, sizeof(struct msix_entry), GFP_KERNEL); if (!txgpio->msix_entries) { err = -ENOMEM; goto out; } - txgpio->line_entries = devm_kzalloc(dev, - sizeof(struct thunderx_line) * ngpio, + txgpio->line_entries = devm_kcalloc(dev, + ngpio, + sizeof(struct thunderx_line), GFP_KERNEL); if (!txgpio->line_entries) { err = -ENOMEM; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c index 428e5eb3444f..f4c474a95875 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c @@ -310,20 +310,20 @@ static int acp_hw_init(void *handle) pm_genpd_init(&adev->acp.acp_genpd->gpd, NULL, false); } - adev->acp.acp_cell = kzalloc(sizeof(struct mfd_cell) * ACP_DEVS, + adev->acp.acp_cell = kcalloc(ACP_DEVS, sizeof(struct mfd_cell), GFP_KERNEL); if (adev->acp.acp_cell == NULL) return -ENOMEM; - adev->acp.acp_res = kzalloc(sizeof(struct resource) * 4, GFP_KERNEL); + adev->acp.acp_res = kcalloc(4, sizeof(struct resource), GFP_KERNEL); if (adev->acp.acp_res == NULL) { kfree(adev->acp.acp_cell); return -ENOMEM; } - i2s_pdata = kzalloc(sizeof(struct i2s_platform_data) * 2, GFP_KERNEL); + i2s_pdata = kcalloc(2, sizeof(struct i2s_platform_data), GFP_KERNEL); if (i2s_pdata == NULL) { kfree(adev->acp.acp_res); kfree(adev->acp.acp_cell); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index 8f6f45567bfa..305143fcc1ce 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -342,15 +342,12 @@ void get_local_mem_info(struct kgd_dev *kgd, mem_info->local_mem_size_public, mem_info->local_mem_size_private); - if (amdgpu_emu_mode == 1) { - mem_info->mem_clk_max = 100; - return; - } - if (amdgpu_sriov_vf(adev)) mem_info->mem_clk_max = adev->clock.default_mclk / 100; - else + else if (adev->powerplay.pp_funcs) mem_info->mem_clk_max = amdgpu_dpm_get_mclk(adev, false) / 100; + else + mem_info->mem_clk_max = 100; } uint64_t get_gpu_clock_counter(struct kgd_dev *kgd) @@ -367,13 +364,12 @@ uint32_t get_max_engine_clock_in_mhz(struct kgd_dev *kgd) struct amdgpu_device *adev = (struct amdgpu_device *)kgd; /* the sclk is in quantas of 10kHz */ - if (amdgpu_emu_mode == 1) - return 100; - if (amdgpu_sriov_vf(adev)) return adev->clock.default_sclk / 100; - - return amdgpu_dpm_get_sclk(adev, false) / 100; + else if (adev->powerplay.pp_funcs) + return amdgpu_dpm_get_sclk(adev, false) / 100; + else + return 100; } void get_cu_info(struct kgd_dev *kgd, struct kfd_cu_info *cu_info) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c index 0ff36d45a597..ea79908dac4c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c @@ -407,7 +407,7 @@ static int kgd_hqd_dump(struct kgd_dev *kgd, (*dump)[i++][1] = RREG32(addr); \ } while (0) - *dump = kmalloc(HQD_N_REGS*2*sizeof(uint32_t), GFP_KERNEL); + *dump = kmalloc_array(HQD_N_REGS * 2, sizeof(uint32_t), GFP_KERNEL); if (*dump == NULL) return -ENOMEM; @@ -504,7 +504,7 @@ static int kgd_hqd_sdma_dump(struct kgd_dev *kgd, #undef HQD_N_REGS #define HQD_N_REGS (19+4) - *dump = kmalloc(HQD_N_REGS*2*sizeof(uint32_t), GFP_KERNEL); + *dump = kmalloc_array(HQD_N_REGS * 2, sizeof(uint32_t), GFP_KERNEL); if (*dump == NULL) return -ENOMEM; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c index 6ef9762b4b00..19dd665e7307 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c @@ -395,7 +395,7 @@ static int kgd_hqd_dump(struct kgd_dev *kgd, (*dump)[i++][1] = RREG32(addr); \ } while (0) - *dump = kmalloc(HQD_N_REGS*2*sizeof(uint32_t), GFP_KERNEL); + *dump = kmalloc_array(HQD_N_REGS * 2, sizeof(uint32_t), GFP_KERNEL); if (*dump == NULL) return -ENOMEM; @@ -491,7 +491,7 @@ static int kgd_hqd_sdma_dump(struct kgd_dev *kgd, #undef HQD_N_REGS #define HQD_N_REGS (19+4+2+3+7) - *dump = kmalloc(HQD_N_REGS*2*sizeof(uint32_t), GFP_KERNEL); + *dump = kmalloc_array(HQD_N_REGS * 2, sizeof(uint32_t), GFP_KERNEL); if (*dump == NULL) return -ENOMEM; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c index f0c0d3953f69..1db60aa5b7f0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c @@ -504,7 +504,7 @@ static int kgd_hqd_dump(struct kgd_dev *kgd, (*dump)[i++][1] = RREG32(addr); \ } while (0) - *dump = kmalloc(HQD_N_REGS*2*sizeof(uint32_t), GFP_KERNEL); + *dump = kmalloc_array(HQD_N_REGS * 2, sizeof(uint32_t), GFP_KERNEL); if (*dump == NULL) return -ENOMEM; @@ -606,7 +606,7 @@ static int kgd_hqd_sdma_dump(struct kgd_dev *kgd, #undef HQD_N_REGS #define HQD_N_REGS (19+6+7+10) - *dump = kmalloc(HQD_N_REGS*2*sizeof(uint32_t), GFP_KERNEL); + *dump = kmalloc_array(HQD_N_REGS * 2, sizeof(uint32_t), GFP_KERNEL); if (*dump == NULL) return -ENOMEM; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c index 1bcb2b247335..daa06e7c5bb7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c @@ -569,7 +569,6 @@ static const struct amdgpu_px_quirk amdgpu_px_quirk_list[] = { { 0x1002, 0x6900, 0x1002, 0x0124, AMDGPU_PX_QUIRK_FORCE_ATPX }, { 0x1002, 0x6900, 0x1028, 0x0812, AMDGPU_PX_QUIRK_FORCE_ATPX }, { 0x1002, 0x6900, 0x1028, 0x0813, AMDGPU_PX_QUIRK_FORCE_ATPX }, - { 0x1002, 0x67DF, 0x1028, 0x0774, AMDGPU_PX_QUIRK_FORCE_ATPX }, { 0, 0, 0, 0, 0 }, }; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 9c1d491d742e..82312a7bc6ad 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -522,6 +522,9 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, struct amdgpu_bo_list_entry *e; struct list_head duplicates; unsigned i, tries = 10; + struct amdgpu_bo *gds; + struct amdgpu_bo *gws; + struct amdgpu_bo *oa; int r; INIT_LIST_HEAD(&p->validated); @@ -652,31 +655,36 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, amdgpu_cs_report_moved_bytes(p->adev, p->bytes_moved, p->bytes_moved_vis); + if (p->bo_list) { - struct amdgpu_bo *gds = p->bo_list->gds_obj; - struct amdgpu_bo *gws = p->bo_list->gws_obj; - struct amdgpu_bo *oa = p->bo_list->oa_obj; struct amdgpu_vm *vm = &fpriv->vm; unsigned i; + gds = p->bo_list->gds_obj; + gws = p->bo_list->gws_obj; + oa = p->bo_list->oa_obj; for (i = 0; i < p->bo_list->num_entries; i++) { struct amdgpu_bo *bo = p->bo_list->array[i].robj; p->bo_list->array[i].bo_va = amdgpu_vm_bo_find(vm, bo); } + } else { + gds = p->adev->gds.gds_gfx_bo; + gws = p->adev->gds.gws_gfx_bo; + oa = p->adev->gds.oa_gfx_bo; + } - if (gds) { - p->job->gds_base = amdgpu_bo_gpu_offset(gds); - p->job->gds_size = amdgpu_bo_size(gds); - } - if (gws) { - p->job->gws_base = amdgpu_bo_gpu_offset(gws); - p->job->gws_size = amdgpu_bo_size(gws); - } - if (oa) { - p->job->oa_base = amdgpu_bo_gpu_offset(oa); - p->job->oa_size = amdgpu_bo_size(oa); - } + if (gds) { + p->job->gds_base = amdgpu_bo_gpu_offset(gds); + p->job->gds_size = amdgpu_bo_size(gds); + } + if (gws) { + p->job->gws_base = amdgpu_bo_gpu_offset(gws); + p->job->gws_size = amdgpu_bo_size(gws); + } + if (oa) { + p->job->oa_base = amdgpu_bo_gpu_offset(oa); + p->job->oa_size = amdgpu_bo_size(oa); } if (!r && p->uf_entry.robj) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 290e279abf0d..3317d1536f4f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -1730,6 +1730,18 @@ static int amdgpu_device_ip_late_set_cg_state(struct amdgpu_device *adev) } } } + + if (adev->powerplay.pp_feature & PP_GFXOFF_MASK) { + /* enable gfx powergating */ + amdgpu_device_ip_set_powergating_state(adev, + AMD_IP_BLOCK_TYPE_GFX, + AMD_PG_STATE_GATE); + /* enable gfxoff */ + amdgpu_device_ip_set_powergating_state(adev, + AMD_IP_BLOCK_TYPE_SMC, + AMD_PG_STATE_GATE); + } + return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.c index def1010ac05e..77ad59ade85c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.c @@ -452,7 +452,7 @@ int amdgpu_parse_extended_power_table(struct amdgpu_device *adev) ATOM_PPLIB_PhaseSheddingLimits_Record *entry; adev->pm.dpm.dyn_state.phase_shedding_limits_table.entries = - kzalloc(psl->ucNumEntries * + kcalloc(psl->ucNumEntries, sizeof(struct amdgpu_phase_shedding_limits_entry), GFP_KERNEL); if (!adev->pm.dpm.dyn_state.phase_shedding_limits_table.entries) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c index 17d6b9fb6d77..dd11b7313ca0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c @@ -369,7 +369,8 @@ int amdgpu_gart_init(struct amdgpu_device *adev) #ifdef CONFIG_DRM_AMDGPU_GART_DEBUGFS /* Allocate pages table */ - adev->gart.pages = vzalloc(sizeof(void *) * adev->gart.num_cpu_pages); + adev->gart.pages = vzalloc(array_size(sizeof(void *), + adev->gart.num_cpu_pages)); if (adev->gart.pages == NULL) return -ENOMEM; #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index 2c8e27370284..5fb156a01774 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -30,6 +30,7 @@ #include <drm/drmP.h> #include <drm/amdgpu_drm.h> #include "amdgpu.h" +#include "amdgpu_display.h" void amdgpu_gem_object_free(struct drm_gem_object *gobj) { @@ -235,6 +236,13 @@ int amdgpu_gem_create_ioctl(struct drm_device *dev, void *data, /* create a gem object to contain this object in */ if (args->in.domains & (AMDGPU_GEM_DOMAIN_GDS | AMDGPU_GEM_DOMAIN_GWS | AMDGPU_GEM_DOMAIN_OA)) { + if (flags & AMDGPU_GEM_CREATE_VM_ALWAYS_VALID) { + /* if gds bo is created from user space, it must be + * passed to bo list + */ + DRM_ERROR("GDS bo cannot be per-vm-bo\n"); + return -EINVAL; + } flags |= AMDGPU_GEM_CREATE_NO_CPU_ACCESS; if (args->in.domains == AMDGPU_GEM_DOMAIN_GDS) size = size << AMDGPU_GDS_SHIFT; @@ -749,15 +757,16 @@ int amdgpu_mode_dumb_create(struct drm_file *file_priv, struct amdgpu_device *adev = dev->dev_private; struct drm_gem_object *gobj; uint32_t handle; + u32 domain; int r; args->pitch = amdgpu_align_pitch(adev, args->width, DIV_ROUND_UP(args->bpp, 8), 0); args->size = (u64)args->pitch * args->height; args->size = ALIGN(args->size, PAGE_SIZE); - - r = amdgpu_gem_object_create(adev, args->size, 0, - AMDGPU_GEM_DOMAIN_VRAM, + domain = amdgpu_bo_get_preferred_pin_domain(adev, + amdgpu_display_supported_domains(adev)); + r = amdgpu_gem_object_create(adev, args->size, 0, domain, AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, false, NULL, &gobj); if (r) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 6a9e46ae7f0a..5e4e1bd90383 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -703,11 +703,7 @@ int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain, /* This assumes only APU display buffers are pinned with (VRAM|GTT). * See function amdgpu_display_supported_domains() */ - if (domain == (AMDGPU_GEM_DOMAIN_VRAM | AMDGPU_GEM_DOMAIN_GTT)) { - domain = AMDGPU_GEM_DOMAIN_VRAM; - if (adev->gmc.real_vram_size <= AMDGPU_SG_THRESHOLD) - domain = AMDGPU_GEM_DOMAIN_GTT; - } + domain = amdgpu_bo_get_preferred_pin_domain(adev, domain); if (bo->pin_count) { uint32_t mem_type = bo->tbo.mem.mem_type; @@ -1066,3 +1062,14 @@ u64 amdgpu_bo_gpu_offset(struct amdgpu_bo *bo) return bo->tbo.offset; } + +uint32_t amdgpu_bo_get_preferred_pin_domain(struct amdgpu_device *adev, + uint32_t domain) +{ + if (domain == (AMDGPU_GEM_DOMAIN_VRAM | AMDGPU_GEM_DOMAIN_GTT)) { + domain = AMDGPU_GEM_DOMAIN_VRAM; + if (adev->gmc.real_vram_size <= AMDGPU_SG_THRESHOLD) + domain = AMDGPU_GEM_DOMAIN_GTT; + } + return domain; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h index 540e03fa159f..731748033878 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h @@ -289,7 +289,8 @@ int amdgpu_bo_restore_from_shadow(struct amdgpu_device *adev, struct reservation_object *resv, struct dma_fence **fence, bool direct); - +uint32_t amdgpu_bo_get_preferred_pin_domain(struct amdgpu_device *adev, + uint32_t domain); /* * sub allocation diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c index d167e8ab76d3..e3878256743a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c @@ -53,7 +53,7 @@ static void amdgpu_do_test_moves(struct amdgpu_device *adev) n -= adev->irq.ih.ring_size; n /= size; - gtt_obj = kzalloc(n * sizeof(*gtt_obj), GFP_KERNEL); + gtt_obj = kcalloc(n, sizeof(*gtt_obj), GFP_KERNEL); if (!gtt_obj) { DRM_ERROR("Failed to allocate %d pointers\n", n); r = 1; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c index 8851bcdfc260..127e87b470ff 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c @@ -49,8 +49,6 @@ static void amdgpu_vcn_idle_work_handler(struct work_struct *work); int amdgpu_vcn_sw_init(struct amdgpu_device *adev) { - struct amdgpu_ring *ring; - struct drm_sched_rq *rq; unsigned long bo_size; const char *fw_name; const struct common_firmware_header *hdr; @@ -84,6 +82,7 @@ int amdgpu_vcn_sw_init(struct amdgpu_device *adev) } hdr = (const struct common_firmware_header *)adev->vcn.fw->data; + adev->vcn.fw_version = le32_to_cpu(hdr->ucode_version); family_id = le32_to_cpu(hdr->ucode_version) & 0xff; version_major = (le32_to_cpu(hdr->ucode_version) >> 24) & 0xff; version_minor = (le32_to_cpu(hdr->ucode_version) >> 8) & 0xff; @@ -102,24 +101,6 @@ int amdgpu_vcn_sw_init(struct amdgpu_device *adev) return r; } - ring = &adev->vcn.ring_dec; - rq = &ring->sched.sched_rq[DRM_SCHED_PRIORITY_NORMAL]; - r = drm_sched_entity_init(&ring->sched, &adev->vcn.entity_dec, - rq, NULL); - if (r != 0) { - DRM_ERROR("Failed setting up VCN dec run queue.\n"); - return r; - } - - ring = &adev->vcn.ring_enc[0]; - rq = &ring->sched.sched_rq[DRM_SCHED_PRIORITY_NORMAL]; - r = drm_sched_entity_init(&ring->sched, &adev->vcn.entity_enc, - rq, NULL); - if (r != 0) { - DRM_ERROR("Failed setting up VCN enc run queue.\n"); - return r; - } - return 0; } @@ -129,10 +110,6 @@ int amdgpu_vcn_sw_fini(struct amdgpu_device *adev) kfree(adev->vcn.saved_bo); - drm_sched_entity_fini(&adev->vcn.ring_dec.sched, &adev->vcn.entity_dec); - - drm_sched_entity_fini(&adev->vcn.ring_enc[0].sched, &adev->vcn.entity_enc); - amdgpu_bo_free_kernel(&adev->vcn.vcpu_bo, &adev->vcn.gpu_addr, (void **)&adev->vcn.cpu_addr); @@ -278,7 +255,7 @@ int amdgpu_vcn_dec_ring_test_ring(struct amdgpu_ring *ring) } static int amdgpu_vcn_dec_send_msg(struct amdgpu_ring *ring, - struct amdgpu_bo *bo, bool direct, + struct amdgpu_bo *bo, struct dma_fence **fence) { struct amdgpu_device *adev = ring->adev; @@ -306,19 +283,12 @@ static int amdgpu_vcn_dec_send_msg(struct amdgpu_ring *ring, } ib->length_dw = 16; - if (direct) { - r = amdgpu_ib_schedule(ring, 1, ib, NULL, &f); - job->fence = dma_fence_get(f); - if (r) - goto err_free; + r = amdgpu_ib_schedule(ring, 1, ib, NULL, &f); + job->fence = dma_fence_get(f); + if (r) + goto err_free; - amdgpu_job_free(job); - } else { - r = amdgpu_job_submit(job, ring, &adev->vcn.entity_dec, - AMDGPU_FENCE_OWNER_UNDEFINED, &f); - if (r) - goto err_free; - } + amdgpu_job_free(job); amdgpu_bo_fence(bo, f, false); amdgpu_bo_unreserve(bo); @@ -370,11 +340,11 @@ static int amdgpu_vcn_dec_get_create_msg(struct amdgpu_ring *ring, uint32_t hand for (i = 14; i < 1024; ++i) msg[i] = cpu_to_le32(0x0); - return amdgpu_vcn_dec_send_msg(ring, bo, true, fence); + return amdgpu_vcn_dec_send_msg(ring, bo, fence); } static int amdgpu_vcn_dec_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle, - bool direct, struct dma_fence **fence) + struct dma_fence **fence) { struct amdgpu_device *adev = ring->adev; struct amdgpu_bo *bo = NULL; @@ -396,7 +366,7 @@ static int amdgpu_vcn_dec_get_destroy_msg(struct amdgpu_ring *ring, uint32_t han for (i = 6; i < 1024; ++i) msg[i] = cpu_to_le32(0x0); - return amdgpu_vcn_dec_send_msg(ring, bo, direct, fence); + return amdgpu_vcn_dec_send_msg(ring, bo, fence); } int amdgpu_vcn_dec_ring_test_ib(struct amdgpu_ring *ring, long timeout) @@ -410,7 +380,7 @@ int amdgpu_vcn_dec_ring_test_ib(struct amdgpu_ring *ring, long timeout) goto error; } - r = amdgpu_vcn_dec_get_destroy_msg(ring, 1, true, &fence); + r = amdgpu_vcn_dec_get_destroy_msg(ring, 1, &fence); if (r) { DRM_ERROR("amdgpu: failed to get destroy ib (%ld).\n", r); goto error; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h index 181e6afa9847..773010b9ff15 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h @@ -67,8 +67,6 @@ struct amdgpu_vcn { struct amdgpu_ring ring_dec; struct amdgpu_ring ring_enc[AMDGPU_VCN_MAX_ENC_RINGS]; struct amdgpu_irq_src irq; - struct drm_sched_entity entity_dec; - struct drm_sched_entity entity_enc; unsigned num_enc_rings; }; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index ccba88cc8c54..b0eb2f537392 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -2123,7 +2123,8 @@ int amdgpu_vm_bo_clear_mappings(struct amdgpu_device *adev, before->last = saddr - 1; before->offset = tmp->offset; before->flags = tmp->flags; - list_add(&before->list, &tmp->list); + before->bo_va = tmp->bo_va; + list_add(&before->list, &tmp->bo_va->invalids); } /* Remember mapping split at the end */ @@ -2133,7 +2134,8 @@ int amdgpu_vm_bo_clear_mappings(struct amdgpu_device *adev, after->offset = tmp->offset; after->offset += after->start - tmp->start; after->flags = tmp->flags; - list_add(&after->list, &tmp->list); + after->bo_va = tmp->bo_va; + list_add(&after->list, &tmp->bo_va->invalids); } list_del(&tmp->list); diff --git a/drivers/gpu/drm/amd/amdgpu/atom.c b/drivers/gpu/drm/amd/amdgpu/atom.c index 69500a8b4e2d..e9934de1b9cf 100644 --- a/drivers/gpu/drm/amd/amdgpu/atom.c +++ b/drivers/gpu/drm/amd/amdgpu/atom.c @@ -1221,7 +1221,7 @@ static int amdgpu_atom_execute_table_locked(struct atom_context *ctx, int index, ectx.abort = false; ectx.last_jump = 0; if (ws) - ectx.ws = kzalloc(4 * ws, GFP_KERNEL); + ectx.ws = kcalloc(4, ws, GFP_KERNEL); else ectx.ws = NULL; diff --git a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c index a266dcf5daed..7fbad2f5f0bd 100644 --- a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c @@ -5679,8 +5679,9 @@ static int ci_parse_power_table(struct amdgpu_device *adev) (mode_info->atom_context->bios + data_offset + le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset)); - adev->pm.dpm.ps = kzalloc(sizeof(struct amdgpu_ps) * - state_array->ucNumEntries, GFP_KERNEL); + adev->pm.dpm.ps = kcalloc(state_array->ucNumEntries, + sizeof(struct amdgpu_ps), + GFP_KERNEL); if (!adev->pm.dpm.ps) return -ENOMEM; power_state_offset = (u8 *)state_array->states; @@ -5927,7 +5928,9 @@ static int ci_dpm_init(struct amdgpu_device *adev) ci_set_private_data_variables_based_on_pptable(adev); adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries = - kzalloc(4 * sizeof(struct amdgpu_clock_voltage_dependency_entry), GFP_KERNEL); + kcalloc(4, + sizeof(struct amdgpu_clock_voltage_dependency_entry), + GFP_KERNEL); if (!adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries) { ci_dpm_fini(adev); return -ENOMEM; diff --git a/drivers/gpu/drm/amd/amdgpu/df_v3_6.c b/drivers/gpu/drm/amd/amdgpu/df_v3_6.c index 60608b3df881..d5ebe566809b 100644 --- a/drivers/gpu/drm/amd/amdgpu/df_v3_6.c +++ b/drivers/gpu/drm/amd/amdgpu/df_v3_6.c @@ -64,7 +64,7 @@ static u32 df_v3_6_get_hbm_channel_number(struct amdgpu_device *adev) int fb_channel_number; fb_channel_number = adev->df_funcs->get_fb_channel_number(adev); - if (fb_channel_number > ARRAY_SIZE(df_v3_6_channel_number)) + if (fb_channel_number >= ARRAY_SIZE(df_v3_6_channel_number)) fb_channel_number = 0; return df_v3_6_channel_number[fb_channel_number]; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index d7530fdfaad5..a69153435ea7 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -111,6 +111,7 @@ static const struct soc15_reg_golden golden_settings_gc_9_0_vg10[] = static const struct soc15_reg_golden golden_settings_gc_9_0_vg20[] = { + SOC15_REG_GOLDEN_VALUE(GC, 0, mmCB_DCC_CONFIG, 0x0f000080, 0x04000080), SOC15_REG_GOLDEN_VALUE(GC, 0, mmCB_HW_CONTROL_2, 0x0f000000, 0x0a000000), SOC15_REG_GOLDEN_VALUE(GC, 0, mmCB_HW_CONTROL_3, 0x30000000, 0x10000000), SOC15_REG_GOLDEN_VALUE(GC, 0, mmGB_ADDR_CONFIG, 0xf3e777ff, 0x22014042), @@ -1837,13 +1838,15 @@ static void gfx_v9_1_parse_ind_reg_list(int *register_list_format, int indirect_offset, int list_size, int *unique_indirect_regs, - int *unique_indirect_reg_count, + int unique_indirect_reg_count, int *indirect_start_offsets, - int *indirect_start_offsets_count) + int *indirect_start_offsets_count, + int max_start_offsets_count) { int idx; for (; indirect_offset < list_size; indirect_offset++) { + WARN_ON(*indirect_start_offsets_count >= max_start_offsets_count); indirect_start_offsets[*indirect_start_offsets_count] = indirect_offset; *indirect_start_offsets_count = *indirect_start_offsets_count + 1; @@ -1851,14 +1854,14 @@ static void gfx_v9_1_parse_ind_reg_list(int *register_list_format, indirect_offset += 2; /* look for the matching indice */ - for (idx = 0; idx < *unique_indirect_reg_count; idx++) { + for (idx = 0; idx < unique_indirect_reg_count; idx++) { if (unique_indirect_regs[idx] == register_list_format[indirect_offset] || !unique_indirect_regs[idx]) break; } - BUG_ON(idx >= *unique_indirect_reg_count); + BUG_ON(idx >= unique_indirect_reg_count); if (!unique_indirect_regs[idx]) unique_indirect_regs[idx] = register_list_format[indirect_offset]; @@ -1893,9 +1896,10 @@ static int gfx_v9_1_init_rlc_save_restore_list(struct amdgpu_device *adev) adev->gfx.rlc.reg_list_format_direct_reg_list_length, adev->gfx.rlc.reg_list_format_size_bytes >> 2, unique_indirect_regs, - &unique_indirect_reg_count, + unique_indirect_reg_count, indirect_start_offsets, - &indirect_start_offsets_count); + &indirect_start_offsets_count, + ARRAY_SIZE(indirect_start_offsets)); /* enable auto inc in case it is disabled */ tmp = RREG32(SOC15_REG_OFFSET(GC, 0, mmRLC_SRM_CNTL)); @@ -3404,11 +3408,6 @@ static int gfx_v9_0_late_init(void *handle) if (r) return r; - r = amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_GFX, - AMD_PG_STATE_GATE); - if (r) - return r; - return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/kv_dpm.c b/drivers/gpu/drm/amd/amdgpu/kv_dpm.c index 17f7f074cedc..7a1e77c93bf1 100644 --- a/drivers/gpu/drm/amd/amdgpu/kv_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/kv_dpm.c @@ -2727,8 +2727,9 @@ static int kv_parse_power_table(struct amdgpu_device *adev) (mode_info->atom_context->bios + data_offset + le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset)); - adev->pm.dpm.ps = kzalloc(sizeof(struct amdgpu_ps) * - state_array->ucNumEntries, GFP_KERNEL); + adev->pm.dpm.ps = kcalloc(state_array->ucNumEntries, + sizeof(struct amdgpu_ps), + GFP_KERNEL); if (!adev->pm.dpm.ps) return -ENOMEM; power_state_offset = (u8 *)state_array->states; diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c index 0c768e388ace..727071fee6f6 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c +++ b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c @@ -47,6 +47,8 @@ MODULE_FIRMWARE("amdgpu/vega20_asd.bin"); #define smnMP1_FIRMWARE_FLAGS 0x3010028 +static uint32_t sos_old_versions[] = {1517616, 1510592, 1448594, 1446554}; + static int psp_v3_1_get_fw_type(struct amdgpu_firmware_info *ucode, enum psp_gfx_fw_type *type) { @@ -210,12 +212,31 @@ static int psp_v3_1_bootloader_load_sysdrv(struct psp_context *psp) return ret; } +static bool psp_v3_1_match_version(struct amdgpu_device *adev, uint32_t ver) +{ + int i; + + if (ver == adev->psp.sos_fw_version) + return true; + + /* + * Double check if the latest four legacy versions. + * If yes, it is still the right version. + */ + for (i = 0; i < sizeof(sos_old_versions) / sizeof(uint32_t); i++) { + if (sos_old_versions[i] == adev->psp.sos_fw_version) + return true; + } + + return false; +} + static int psp_v3_1_bootloader_load_sos(struct psp_context *psp) { int ret; unsigned int psp_gfxdrv_command_reg = 0; struct amdgpu_device *adev = psp->adev; - uint32_t sol_reg; + uint32_t sol_reg, ver; /* Check sOS sign of life register to confirm sys driver and sOS * are already been loaded. @@ -248,6 +269,10 @@ static int psp_v3_1_bootloader_load_sos(struct psp_context *psp) RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_81), 0, true); + ver = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_58); + if (!psp_v3_1_match_version(adev, ver)) + DRM_WARN("SOS version doesn't match\n"); + return ret; } diff --git a/drivers/gpu/drm/amd/amdgpu/si_dpm.c b/drivers/gpu/drm/amd/amdgpu/si_dpm.c index b12d7c9d42a0..5c97a3671726 100644 --- a/drivers/gpu/drm/amd/amdgpu/si_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/si_dpm.c @@ -7242,8 +7242,9 @@ static int si_parse_power_table(struct amdgpu_device *adev) (mode_info->atom_context->bios + data_offset + le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset)); - adev->pm.dpm.ps = kzalloc(sizeof(struct amdgpu_ps) * - state_array->ucNumEntries, GFP_KERNEL); + adev->pm.dpm.ps = kcalloc(state_array->ucNumEntries, + sizeof(struct amdgpu_ps), + GFP_KERNEL); if (!adev->pm.dpm.ps) return -ENOMEM; power_state_offset = (u8 *)state_array->states; @@ -7346,7 +7347,9 @@ static int si_dpm_init(struct amdgpu_device *adev) return ret; adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries = - kzalloc(4 * sizeof(struct amdgpu_clock_voltage_dependency_entry), GFP_KERNEL); + kcalloc(4, + sizeof(struct amdgpu_clock_voltage_dependency_entry), + GFP_KERNEL); if (!adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries) { amdgpu_free_extended_power_table(adev); return -ENOMEM; diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.c b/drivers/gpu/drm/amd/amdgpu/soc15.c index 68b4a22a8892..83f2717fcf81 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc15.c +++ b/drivers/gpu/drm/amd/amdgpu/soc15.c @@ -685,6 +685,7 @@ static int soc15_common_early_init(void *handle) AMD_CG_SUPPORT_BIF_MGCG | AMD_CG_SUPPORT_BIF_LS | AMD_CG_SUPPORT_HDP_MGCG | + AMD_CG_SUPPORT_HDP_LS | AMD_CG_SUPPORT_ROM_MGCG | AMD_CG_SUPPORT_VCE_MGCG | AMD_CG_SUPPORT_UVD_MGCG; diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c index 110b294ebed3..29684c3ea4ef 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c @@ -769,14 +769,14 @@ static int vcn_v1_0_stop(struct amdgpu_device *adev) return 0; } -bool vcn_v1_0_is_idle(void *handle) +static bool vcn_v1_0_is_idle(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; return (RREG32_SOC15(VCN, 0, mmUVD_STATUS) == 0x2); } -int vcn_v1_0_wait_for_idle(void *handle) +static int vcn_v1_0_wait_for_idle(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; int ret = 0; 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 f9b9ab90558c..f9add85157e7 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -46,6 +46,7 @@ #include <linux/moduleparam.h> #include <linux/version.h> #include <linux/types.h> +#include <linux/pm_runtime.h> #include <drm/drmP.h> #include <drm/drm_atomic.h> @@ -2095,12 +2096,6 @@ convert_color_depth_from_display_info(const struct drm_connector *connector) { uint32_t bpc = connector->display_info.bpc; - /* Limited color depth to 8bit - * TODO: Still need to handle deep color - */ - if (bpc > 8) - bpc = 8; - switch (bpc) { case 0: /* Temporary Work around, DRM don't parse color depth for @@ -2316,27 +2311,22 @@ decide_crtc_timing_for_drm_display_mode(struct drm_display_mode *drm_mode, } } -static int create_fake_sink(struct amdgpu_dm_connector *aconnector) +static struct dc_sink * +create_fake_sink(struct amdgpu_dm_connector *aconnector) { - struct dc_sink *sink = NULL; struct dc_sink_init_data sink_init_data = { 0 }; - + struct dc_sink *sink = NULL; sink_init_data.link = aconnector->dc_link; sink_init_data.sink_signal = aconnector->dc_link->connector_signal; sink = dc_sink_create(&sink_init_data); if (!sink) { DRM_ERROR("Failed to create sink!\n"); - return -ENOMEM; + return NULL; } - sink->sink_signal = SIGNAL_TYPE_VIRTUAL; - aconnector->fake_enable = true; - - aconnector->dc_sink = sink; - aconnector->dc_link->local_sink = sink; - return 0; + return sink; } static void set_multisync_trigger_params( @@ -2399,7 +2389,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, struct dc_stream_state *stream = NULL; struct drm_display_mode mode = *drm_mode; bool native_mode_found = false; - + struct dc_sink *sink = NULL; if (aconnector == NULL) { DRM_ERROR("aconnector is NULL!\n"); return stream; @@ -2417,15 +2407,18 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, return stream; } - if (create_fake_sink(aconnector)) + sink = create_fake_sink(aconnector); + if (!sink) return stream; + } else { + sink = aconnector->dc_sink; } - stream = dc_create_stream_for_sink(aconnector->dc_sink); + stream = dc_create_stream_for_sink(sink); if (stream == NULL) { DRM_ERROR("Failed to create stream for sink!\n"); - return stream; + goto finish; } list_for_each_entry(preferred_mode, &aconnector->base.modes, head) { @@ -2464,12 +2457,15 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, fill_audio_info( &stream->audio_info, drm_connector, - aconnector->dc_sink); + sink); update_stream_signal(stream); if (dm_state && dm_state->freesync_capable) stream->ignore_msa_timing_param = true; +finish: + if (sink && sink->sink_signal == SIGNAL_TYPE_VIRTUAL) + dc_sink_release(sink); return stream; } @@ -2714,6 +2710,9 @@ void amdgpu_dm_connector_funcs_reset(struct drm_connector *connector) struct dm_connector_state *state = to_dm_connector_state(connector->state); + if (connector->state) + __drm_atomic_helper_connector_destroy_state(connector->state); + kfree(state); state = kzalloc(sizeof(*state), GFP_KERNEL); @@ -2724,8 +2723,7 @@ void amdgpu_dm_connector_funcs_reset(struct drm_connector *connector) state->underscan_hborder = 0; state->underscan_vborder = 0; - connector->state = &state->base; - connector->state->connector = connector; + __drm_atomic_helper_connector_reset(connector, &state->base); } } @@ -3083,17 +3081,6 @@ static int dm_plane_helper_prepare_fb(struct drm_plane *plane, } } - /* It's a hack for s3 since in 4.9 kernel filter out cursor buffer - * prepare and cleanup in drm_atomic_helper_prepare_planes - * and drm_atomic_helper_cleanup_planes because fb doens't in s3. - * IN 4.10 kernel this code should be removed and amdgpu_device_suspend - * code touching fram buffers should be avoided for DC. - */ - if (plane->type == DRM_PLANE_TYPE_CURSOR) { - struct amdgpu_crtc *acrtc = to_amdgpu_crtc(new_state->crtc); - - acrtc->cursor_bo = obj; - } return 0; } @@ -4281,6 +4268,8 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) if (dm_old_crtc_state->stream) remove_stream(adev, acrtc, dm_old_crtc_state->stream); + pm_runtime_get_noresume(dev->dev); + acrtc->enabled = true; acrtc->hw_mode = new_crtc_state->mode; crtc->hwmode = new_crtc_state->mode; @@ -4469,6 +4458,16 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) drm_atomic_helper_wait_for_flip_done(dev, state); drm_atomic_helper_cleanup_planes(dev, state); + + /* Finally, drop a runtime PM reference for each newly disabled CRTC, + * so we can put the GPU into runtime suspend if we're not driving any + * displays anymore + */ + pm_runtime_mark_last_busy(dev->dev); + for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { + if (old_crtc_state->active && !new_crtc_state->active) + pm_runtime_put_autosuspend(dev->dev); + } } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c index bd449351803f..ec304b1a5973 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c @@ -435,7 +435,7 @@ bool dm_helpers_submit_i2c( return false; } - msgs = kzalloc(num * sizeof(struct i2c_msg), GFP_KERNEL); + msgs = kcalloc(num, sizeof(struct i2c_msg), GFP_KERNEL); if (!msgs) return false; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c index 4be21bf54749..a910f01838ab 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c @@ -555,6 +555,9 @@ static inline int dm_irq_state(struct amdgpu_device *adev, return 0; } + if (acrtc->otg_inst == -1) + return 0; + irq_source = dal_irq_type + acrtc->otg_inst; st = (state == AMDGPU_IRQ_STATE_ENABLE); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c index 0229c7edb8ad..5a3346124a01 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c @@ -234,6 +234,33 @@ static void pp_to_dc_clock_levels( } } +static void pp_to_dc_clock_levels_with_latency( + const struct pp_clock_levels_with_latency *pp_clks, + struct dm_pp_clock_levels_with_latency *clk_level_info, + enum dm_pp_clock_type dc_clk_type) +{ + uint32_t i; + + if (pp_clks->num_levels > DM_PP_MAX_CLOCK_LEVELS) { + DRM_INFO("DM_PPLIB: Warning: %s clock: number of levels %d exceeds maximum of %d!\n", + DC_DECODE_PP_CLOCK_TYPE(dc_clk_type), + pp_clks->num_levels, + DM_PP_MAX_CLOCK_LEVELS); + + clk_level_info->num_levels = DM_PP_MAX_CLOCK_LEVELS; + } else + clk_level_info->num_levels = pp_clks->num_levels; + + DRM_DEBUG("DM_PPLIB: values for %s clock\n", + DC_DECODE_PP_CLOCK_TYPE(dc_clk_type)); + + for (i = 0; i < clk_level_info->num_levels; i++) { + DRM_DEBUG("DM_PPLIB:\t %d\n", pp_clks->data[i].clocks_in_khz); + clk_level_info->data[i].clocks_in_khz = pp_clks->data[i].clocks_in_khz; + clk_level_info->data[i].latency_in_us = pp_clks->data[i].latency_in_us; + } +} + bool dm_pp_get_clock_levels_by_type( const struct dc_context *ctx, enum dm_pp_clock_type clk_type, @@ -311,8 +338,22 @@ bool dm_pp_get_clock_levels_by_type_with_latency( enum dm_pp_clock_type clk_type, struct dm_pp_clock_levels_with_latency *clk_level_info) { - /* TODO: to be implemented */ - return false; + struct amdgpu_device *adev = ctx->driver_context; + void *pp_handle = adev->powerplay.pp_handle; + struct pp_clock_levels_with_latency pp_clks = { 0 }; + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + + if (!pp_funcs || !pp_funcs->get_clock_by_type_with_latency) + return false; + + if (pp_funcs->get_clock_by_type_with_latency(pp_handle, + dc_to_pp_clock_type(clk_type), + &pp_clks)) + return false; + + pp_to_dc_clock_levels_with_latency(&pp_clks, clk_level_info, clk_type); + + return true; } bool dm_pp_get_clock_levels_by_type_with_voltage( diff --git a/drivers/gpu/drm/amd/display/dc/basics/fixpt31_32.c b/drivers/gpu/drm/amd/display/dc/basics/fixpt31_32.c index e61dd97d0928..f28989860fd8 100644 --- a/drivers/gpu/drm/amd/display/dc/basics/fixpt31_32.c +++ b/drivers/gpu/drm/amd/display/dc/basics/fixpt31_32.c @@ -449,6 +449,11 @@ static inline unsigned int clamp_ux_dy( return min_clamp; } +unsigned int dc_fixpt_u3d19(struct fixed31_32 arg) +{ + return ux_dy(arg.value, 3, 19); +} + unsigned int dc_fixpt_u2d19(struct fixed31_32 arg) { return ux_dy(arg.value, 2, 19); diff --git a/drivers/gpu/drm/amd/display/dc/basics/logger.c b/drivers/gpu/drm/amd/display/dc/basics/logger.c index 738a818d58d1..0866874ae8c6 100644 --- a/drivers/gpu/drm/amd/display/dc/basics/logger.c +++ b/drivers/gpu/drm/amd/display/dc/basics/logger.c @@ -364,7 +364,7 @@ void dm_logger_open( entry->type = log_type; entry->logger = logger; - entry->buf = kzalloc(DAL_LOGGER_BUFFER_MAX_SIZE * sizeof(char), + entry->buf = kzalloc(DAL_LOGGER_BUFFER_MAX_SIZE, GFP_KERNEL); entry->buf_offset = 0; diff --git a/drivers/gpu/drm/amd/display/dc/basics/vector.c b/drivers/gpu/drm/amd/display/dc/basics/vector.c index 217b8f1f7bf6..d28e9cf0e961 100644 --- a/drivers/gpu/drm/amd/display/dc/basics/vector.c +++ b/drivers/gpu/drm/amd/display/dc/basics/vector.c @@ -40,7 +40,7 @@ bool dal_vector_construct( return false; } - vector->container = kzalloc(struct_size * capacity, GFP_KERNEL); + vector->container = kcalloc(capacity, struct_size, GFP_KERNEL); if (vector->container == NULL) return false; vector->capacity = capacity; @@ -67,7 +67,7 @@ bool dal_vector_presized_costruct( return false; } - vector->container = kzalloc(struct_size * count, GFP_KERNEL); + vector->container = kcalloc(count, struct_size, GFP_KERNEL); if (vector->container == NULL) return false; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c index 7d609c71394b..7857cb42b3e6 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c @@ -1630,17 +1630,42 @@ static enum dc_status read_hpd_rx_irq_data( struct dc_link *link, union hpd_irq_data *irq_data) { + static enum dc_status retval; + /* The HW reads 16 bytes from 200h on HPD, * but if we get an AUX_DEFER, the HW cannot retry * and this causes the CTS tests 4.3.2.1 - 3.2.4 to * fail, so we now explicitly read 6 bytes which is * the req from the above mentioned test cases. + * + * For DP 1.4 we need to read those from 2002h range. */ - return core_link_read_dpcd( - link, - DP_SINK_COUNT, - irq_data->raw, - sizeof(union hpd_irq_data)); + if (link->dpcd_caps.dpcd_rev.raw < DPCD_REV_14) + retval = core_link_read_dpcd( + link, + DP_SINK_COUNT, + irq_data->raw, + sizeof(union hpd_irq_data)); + else { + /* Read 2 bytes at this location,... */ + retval = core_link_read_dpcd( + link, + DP_SINK_COUNT_ESI, + irq_data->raw, + 2); + + if (retval != DC_OK) + return retval; + + /* ... then read remaining 4 at the other location */ + retval = core_link_read_dpcd( + link, + DP_LANE0_1_STATUS_ESI, + &irq_data->raw[2], + 4); + } + + return retval; } static bool allow_hpd_rx_irq(const struct dc_link *link) @@ -2278,7 +2303,7 @@ static void dp_wa_power_up_0010FA(struct dc_link *link, uint8_t *dpcd_data, static bool retrieve_link_cap(struct dc_link *link) { - uint8_t dpcd_data[DP_TRAINING_AUX_RD_INTERVAL - DP_DPCD_REV + 1]; + uint8_t dpcd_data[DP_ADAPTER_CAP - DP_DPCD_REV + 1]; union down_stream_port_count down_strm_port_count; union edp_configuration_cap edp_config_cap; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c index 599c7ab6befe..88b09dd758ba 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c @@ -1079,13 +1079,15 @@ static void get_ss_info_from_atombios( if (*ss_entries_num == 0) return; - ss_info = kzalloc(sizeof(struct spread_spectrum_info) * (*ss_entries_num), + ss_info = kcalloc(*ss_entries_num, + sizeof(struct spread_spectrum_info), GFP_KERNEL); ss_info_cur = ss_info; if (ss_info == NULL) return; - ss_data = kzalloc(sizeof(struct spread_spectrum_data) * (*ss_entries_num), + ss_data = kcalloc(*ss_entries_num, + sizeof(struct spread_spectrum_data), GFP_KERNEL); if (ss_data == NULL) goto out_free_info; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c index 0a6d483dc046..c0e813c7ddd4 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c @@ -72,7 +72,8 @@ static void dce110_update_generic_info_packet( uint32_t max_retries = 50; /*we need turn on clock before programming AFMT block*/ - REG_UPDATE(AFMT_CNTL, AFMT_AUDIO_CLOCK_EN, 1); + if (REG(AFMT_CNTL)) + REG_UPDATE(AFMT_CNTL, AFMT_AUDIO_CLOCK_EN, 1); if (REG(AFMT_VBI_PACKET_CONTROL1)) { if (packet_index >= 8) @@ -719,7 +720,8 @@ static void dce110_stream_encoder_update_hdmi_info_packets( const uint32_t *content = (const uint32_t *) &info_frame->avi.sb[0]; /*we need turn on clock before programming AFMT block*/ - REG_UPDATE(AFMT_CNTL, AFMT_AUDIO_CLOCK_EN, 1); + if (REG(AFMT_CNTL)) + REG_UPDATE(AFMT_CNTL, AFMT_AUDIO_CLOCK_EN, 1); REG_WRITE(AFMT_AVI_INFO0, content[0]); diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c index 9150d2694450..e2994d337044 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c @@ -121,10 +121,10 @@ static void reset_lb_on_vblank(struct dc_context *ctx) frame_count = dm_read_reg(ctx, mmCRTC_STATUS_FRAME_COUNT); - for (retry = 100; retry > 0; retry--) { + for (retry = 10000; retry > 0; retry--) { if (frame_count != dm_read_reg(ctx, mmCRTC_STATUS_FRAME_COUNT)) break; - msleep(1); + udelay(10); } if (!retry) dm_error("Frame count did not increase for 100ms.\n"); @@ -147,14 +147,14 @@ static void wait_for_fbc_state_changed( uint32_t addr = mmFBC_STATUS; uint32_t value; - while (counter < 10) { + while (counter < 1000) { value = dm_read_reg(cp110->base.ctx, addr); if (get_reg_field_value( value, FBC_STATUS, FBC_ENABLE_STATUS) == enabled) break; - msleep(10); + udelay(100); counter++; } diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c index a92fb0aa2ff3..c29052b6da5a 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c @@ -1004,9 +1004,9 @@ void dce110_disable_stream(struct pipe_ctx *pipe_ctx, int option) /*don't free audio if it is from retrain or internal disable stream*/ if (option == FREE_ACQUIRED_RESOURCE && dc->caps.dynamic_audio == true) { /*we have to dynamic arbitrate the audio endpoints*/ - pipe_ctx->stream_res.audio = NULL; /*we free the resource, need reset is_audio_acquired*/ update_audio_usage(&dc->current_state->res_ctx, dc->res_pool, pipe_ctx->stream_res.audio, false); + pipe_ctx->stream_res.audio = NULL; } /* TODO: notify audio driver for if audio modes list changed diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c index 46a35c7f01df..c69fa4bfab0a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c @@ -132,8 +132,7 @@ void dpp_set_gamut_remap_bypass(struct dcn10_dpp *dpp) #define IDENTITY_RATIO(ratio) (dc_fixpt_u2d19(ratio) == (1 << 19)) - -bool dpp_get_optimal_number_of_taps( +static bool dpp_get_optimal_number_of_taps( struct dpp *dpp, struct scaler_data *scl_data, const struct scaling_taps *in_taps) diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h index 5944a3ba0409..e862cafa6501 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h @@ -1424,12 +1424,8 @@ void dpp1_set_degamma( enum ipp_degamma_mode mode); void dpp1_set_degamma_pwl(struct dpp *dpp_base, - const struct pwl_params *params); + const struct pwl_params *params); -bool dpp_get_optimal_number_of_taps( - struct dpp *dpp, - struct scaler_data *scl_data, - const struct scaling_taps *in_taps); void dpp_read_state(struct dpp *dpp_base, struct dcn_dpp_state *s); diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c index 4ddd6273d5a5..f862fd148cca 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c @@ -565,16 +565,16 @@ static void dpp1_dscl_set_manual_ratio_init( uint32_t init_int = 0; REG_SET(SCL_HORZ_FILTER_SCALE_RATIO, 0, - SCL_H_SCALE_RATIO, dc_fixpt_u2d19(data->ratios.horz) << 5); + SCL_H_SCALE_RATIO, dc_fixpt_u3d19(data->ratios.horz) << 5); REG_SET(SCL_VERT_FILTER_SCALE_RATIO, 0, - SCL_V_SCALE_RATIO, dc_fixpt_u2d19(data->ratios.vert) << 5); + SCL_V_SCALE_RATIO, dc_fixpt_u3d19(data->ratios.vert) << 5); REG_SET(SCL_HORZ_FILTER_SCALE_RATIO_C, 0, - SCL_H_SCALE_RATIO_C, dc_fixpt_u2d19(data->ratios.horz_c) << 5); + SCL_H_SCALE_RATIO_C, dc_fixpt_u3d19(data->ratios.horz_c) << 5); REG_SET(SCL_VERT_FILTER_SCALE_RATIO_C, 0, - SCL_V_SCALE_RATIO_C, dc_fixpt_u2d19(data->ratios.vert_c) << 5); + SCL_V_SCALE_RATIO_C, dc_fixpt_u3d19(data->ratios.vert_c) << 5); /* * 0.24 format for fraction, first five bits zeroed diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c index d2ab78b35a7a..c28085be39ff 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c @@ -396,11 +396,15 @@ bool hubp1_program_surface_flip_and_addr( if (address->grph_stereo.right_addr.quad_part == 0) break; - REG_UPDATE_4(DCSURF_SURFACE_CONTROL, + REG_UPDATE_8(DCSURF_SURFACE_CONTROL, PRIMARY_SURFACE_TMZ, address->tmz_surface, PRIMARY_SURFACE_TMZ_C, address->tmz_surface, PRIMARY_META_SURFACE_TMZ, address->tmz_surface, - PRIMARY_META_SURFACE_TMZ_C, address->tmz_surface); + PRIMARY_META_SURFACE_TMZ_C, address->tmz_surface, + SECONDARY_SURFACE_TMZ, address->tmz_surface, + SECONDARY_SURFACE_TMZ_C, address->tmz_surface, + SECONDARY_META_SURFACE_TMZ, address->tmz_surface, + SECONDARY_META_SURFACE_TMZ_C, address->tmz_surface); if (address->grph_stereo.right_meta_addr.quad_part != 0) { @@ -459,9 +463,11 @@ void hubp1_dcc_control(struct hubp *hubp, bool enable, uint32_t dcc_ind_64b_blk = independent_64b_blks ? 1 : 0; struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); - REG_UPDATE_2(DCSURF_SURFACE_CONTROL, + REG_UPDATE_4(DCSURF_SURFACE_CONTROL, PRIMARY_SURFACE_DCC_EN, dcc_en, - PRIMARY_SURFACE_DCC_IND_64B_BLK, dcc_ind_64b_blk); + PRIMARY_SURFACE_DCC_IND_64B_BLK, dcc_ind_64b_blk, + SECONDARY_SURFACE_DCC_EN, dcc_en, + SECONDARY_SURFACE_DCC_IND_64B_BLK, dcc_ind_64b_blk); } void hubp1_program_surface_config( diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h index af384034398f..d901d5092969 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h @@ -312,6 +312,12 @@ HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, PRIMARY_META_SURFACE_TMZ_C, mask_sh),\ HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, PRIMARY_SURFACE_DCC_EN, mask_sh),\ HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, PRIMARY_SURFACE_DCC_IND_64B_BLK, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, SECONDARY_SURFACE_TMZ, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, SECONDARY_SURFACE_TMZ_C, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, SECONDARY_META_SURFACE_TMZ, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, SECONDARY_META_SURFACE_TMZ_C, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, SECONDARY_SURFACE_DCC_EN, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, SECONDARY_SURFACE_DCC_IND_64B_BLK, mask_sh),\ HUBP_SF(HUBPRET0_HUBPRET_CONTROL, DET_BUF_PLANE1_BASE_ADDRESS, mask_sh),\ HUBP_SF(HUBPRET0_HUBPRET_CONTROL, CROSSBAR_SRC_CB_B, mask_sh),\ HUBP_SF(HUBPRET0_HUBPRET_CONTROL, CROSSBAR_SRC_CR_R, mask_sh),\ @@ -489,6 +495,8 @@ type SECONDARY_META_SURFACE_TMZ_C;\ type PRIMARY_SURFACE_DCC_EN;\ type PRIMARY_SURFACE_DCC_IND_64B_BLK;\ + type SECONDARY_SURFACE_DCC_EN;\ + type SECONDARY_SURFACE_DCC_IND_64B_BLK;\ type DET_BUF_PLANE1_BASE_ADDRESS;\ type CROSSBAR_SRC_CB_B;\ type CROSSBAR_SRC_CR_R;\ diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c index 653b7b2efe2e..c928ee4cd382 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c @@ -319,6 +319,10 @@ void enc1_stream_encoder_dp_set_stream_attribute( REG_UPDATE(DP_PIXEL_FORMAT, DP_COMPONENT_DEPTH, DP_COMPONENT_PIXEL_DEPTH_12BPC); break; + case COLOR_DEPTH_161616: + REG_UPDATE(DP_PIXEL_FORMAT, DP_COMPONENT_DEPTH, + DP_COMPONENT_PIXEL_DEPTH_16BPC); + break; default: REG_UPDATE(DP_PIXEL_FORMAT, DP_COMPONENT_DEPTH, DP_COMPONENT_PIXEL_DEPTH_6BPC); diff --git a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c index 80038e0e610f..ab5483c0c502 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c @@ -98,7 +98,8 @@ struct gpio_service *dal_gpio_service_create( if (number_of_bits) { uint32_t index_of_uint = 0; - slot = kzalloc(number_of_uints * sizeof(uint32_t), + slot = kcalloc(number_of_uints, + sizeof(uint32_t), GFP_KERNEL); if (!slot) { diff --git a/drivers/gpu/drm/amd/display/include/fixed31_32.h b/drivers/gpu/drm/amd/display/include/fixed31_32.h index bb0d4ebba9f0..a981b3e99ab3 100644 --- a/drivers/gpu/drm/amd/display/include/fixed31_32.h +++ b/drivers/gpu/drm/amd/display/include/fixed31_32.h @@ -496,6 +496,8 @@ static inline int dc_fixpt_ceil(struct fixed31_32 arg) * fractional */ +unsigned int dc_fixpt_u3d19(struct fixed31_32 arg); + unsigned int dc_fixpt_u2d19(struct fixed31_32 arg); unsigned int dc_fixpt_u0d19(struct fixed31_32 arg); diff --git a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c index 0cd111d59018..eee0dfad6962 100644 --- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c +++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c @@ -1274,19 +1274,22 @@ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf, output_tf->type = TF_TYPE_DISTRIBUTED_POINTS; - rgb_user = kvzalloc(sizeof(*rgb_user) * (ramp->num_entries + _EXTRA_POINTS), + rgb_user = kvcalloc(ramp->num_entries + _EXTRA_POINTS, + sizeof(*rgb_user), GFP_KERNEL); if (!rgb_user) goto rgb_user_alloc_fail; - rgb_regamma = kvzalloc(sizeof(*rgb_regamma) * (MAX_HW_POINTS + _EXTRA_POINTS), + rgb_regamma = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS, + sizeof(*rgb_regamma), GFP_KERNEL); if (!rgb_regamma) goto rgb_regamma_alloc_fail; - axix_x = kvzalloc(sizeof(*axix_x) * (ramp->num_entries + 3), + axix_x = kvcalloc(ramp->num_entries + 3, sizeof(*axix_x), GFP_KERNEL); if (!axix_x) goto axix_x_alloc_fail; - coeff = kvzalloc(sizeof(*coeff) * (MAX_HW_POINTS + _EXTRA_POINTS), GFP_KERNEL); + coeff = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS, sizeof(*coeff), + GFP_KERNEL); if (!coeff) goto coeff_alloc_fail; @@ -1413,13 +1416,15 @@ bool calculate_user_regamma_ramp(struct dc_transfer_func *output_tf, output_tf->type = TF_TYPE_DISTRIBUTED_POINTS; - rgb_user = kzalloc(sizeof(*rgb_user) * (GAMMA_RGB_256_ENTRIES + _EXTRA_POINTS), - GFP_KERNEL); + rgb_user = kcalloc(GAMMA_RGB_256_ENTRIES + _EXTRA_POINTS, + sizeof(*rgb_user), + GFP_KERNEL); if (!rgb_user) goto rgb_user_alloc_fail; - rgb_regamma = kzalloc(sizeof(*rgb_regamma) * (MAX_HW_POINTS + _EXTRA_POINTS), - GFP_KERNEL); + rgb_regamma = kcalloc(MAX_HW_POINTS + _EXTRA_POINTS, + sizeof(*rgb_regamma), + GFP_KERNEL); if (!rgb_regamma) goto rgb_regamma_alloc_fail; @@ -1480,19 +1485,21 @@ bool mod_color_calculate_degamma_params(struct dc_transfer_func *input_tf, input_tf->type = TF_TYPE_DISTRIBUTED_POINTS; - rgb_user = kvzalloc(sizeof(*rgb_user) * (ramp->num_entries + _EXTRA_POINTS), + rgb_user = kvcalloc(ramp->num_entries + _EXTRA_POINTS, + sizeof(*rgb_user), GFP_KERNEL); if (!rgb_user) goto rgb_user_alloc_fail; - curve = kvzalloc(sizeof(*curve) * (MAX_HW_POINTS + _EXTRA_POINTS), + curve = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS, sizeof(*curve), GFP_KERNEL); if (!curve) goto curve_alloc_fail; - axix_x = kvzalloc(sizeof(*axix_x) * (ramp->num_entries + _EXTRA_POINTS), + axix_x = kvcalloc(ramp->num_entries + _EXTRA_POINTS, sizeof(*axix_x), GFP_KERNEL); if (!axix_x) goto axix_x_alloc_fail; - coeff = kvzalloc(sizeof(*coeff) * (MAX_HW_POINTS + _EXTRA_POINTS), GFP_KERNEL); + coeff = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS, sizeof(*coeff), + GFP_KERNEL); if (!coeff) goto coeff_alloc_fail; @@ -1569,8 +1576,8 @@ bool mod_color_calculate_curve(enum dc_transfer_func_predefined trans, } ret = true; } else if (trans == TRANSFER_FUNCTION_PQ) { - rgb_regamma = kvzalloc(sizeof(*rgb_regamma) * - (MAX_HW_POINTS + _EXTRA_POINTS), + rgb_regamma = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS, + sizeof(*rgb_regamma), GFP_KERNEL); if (!rgb_regamma) goto rgb_regamma_alloc_fail; @@ -1594,8 +1601,8 @@ bool mod_color_calculate_curve(enum dc_transfer_func_predefined trans, kvfree(rgb_regamma); } else if (trans == TRANSFER_FUNCTION_SRGB || trans == TRANSFER_FUNCTION_BT709) { - rgb_regamma = kvzalloc(sizeof(*rgb_regamma) * - (MAX_HW_POINTS + _EXTRA_POINTS), + rgb_regamma = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS, + sizeof(*rgb_regamma), GFP_KERNEL); if (!rgb_regamma) goto rgb_regamma_alloc_fail; @@ -1638,8 +1645,8 @@ bool mod_color_calculate_degamma_curve(enum dc_transfer_func_predefined trans, } ret = true; } else if (trans == TRANSFER_FUNCTION_PQ) { - rgb_degamma = kvzalloc(sizeof(*rgb_degamma) * - (MAX_HW_POINTS + _EXTRA_POINTS), + rgb_degamma = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS, + sizeof(*rgb_degamma), GFP_KERNEL); if (!rgb_degamma) goto rgb_degamma_alloc_fail; @@ -1658,8 +1665,8 @@ bool mod_color_calculate_degamma_curve(enum dc_transfer_func_predefined trans, kvfree(rgb_degamma); } else if (trans == TRANSFER_FUNCTION_SRGB || trans == TRANSFER_FUNCTION_BT709) { - rgb_degamma = kvzalloc(sizeof(*rgb_degamma) * - (MAX_HW_POINTS + _EXTRA_POINTS), + rgb_degamma = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS, + sizeof(*rgb_degamma), GFP_KERNEL); if (!rgb_degamma) goto rgb_degamma_alloc_fail; diff --git a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c index 27d4003aa2c7..fa344ceafc17 100644 --- a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c +++ b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c @@ -155,7 +155,8 @@ struct mod_freesync *mod_freesync_create(struct dc *dc) if (core_freesync == NULL) goto fail_alloc_context; - core_freesync->map = kzalloc(sizeof(struct freesync_entity) * MOD_FREESYNC_MAX_CONCURRENT_STREAMS, + core_freesync->map = kcalloc(MOD_FREESYNC_MAX_CONCURRENT_STREAMS, + sizeof(struct freesync_entity), GFP_KERNEL); if (core_freesync->map == NULL) diff --git a/drivers/gpu/drm/amd/display/modules/stats/stats.c b/drivers/gpu/drm/amd/display/modules/stats/stats.c index 3f7d47fdc367..710852ad03f3 100644 --- a/drivers/gpu/drm/amd/display/modules/stats/stats.c +++ b/drivers/gpu/drm/amd/display/modules/stats/stats.c @@ -141,19 +141,17 @@ struct mod_stats *mod_stats_create(struct dc *dc) else core_stats->entries = reg_data; } - core_stats->time = kzalloc( - sizeof(struct stats_time_cache) * - core_stats->entries, + core_stats->time = kcalloc(core_stats->entries, + sizeof(struct stats_time_cache), GFP_KERNEL); if (core_stats->time == NULL) goto fail_construct_time; core_stats->event_entries = DAL_STATS_EVENT_ENTRIES_DEFAULT; - core_stats->events = kzalloc( - sizeof(struct stats_event_cache) * - core_stats->event_entries, - GFP_KERNEL); + core_stats->events = kcalloc(core_stats->event_entries, + sizeof(struct stats_event_cache), + GFP_KERNEL); if (core_stats->events == NULL) goto fail_construct_events; diff --git a/drivers/gpu/drm/amd/include/asic_reg/df/df_3_6_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/df/df_3_6_sh_mask.h index 88f7c69df6b9..06fac509e987 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/df/df_3_6_sh_mask.h +++ b/drivers/gpu/drm/amd/include/asic_reg/df/df_3_6_sh_mask.h @@ -36,13 +36,13 @@ /* DF_CS_AON0_DramBaseAddress0 */ #define DF_CS_UMC_AON0_DramBaseAddress0__AddrRngVal__SHIFT 0x0 #define DF_CS_UMC_AON0_DramBaseAddress0__LgcyMmioHoleEn__SHIFT 0x1 -#define DF_CS_UMC_AON0_DramBaseAddress0__IntLvNumChan__SHIFT 0x4 -#define DF_CS_UMC_AON0_DramBaseAddress0__IntLvAddrSel__SHIFT 0x8 +#define DF_CS_UMC_AON0_DramBaseAddress0__IntLvNumChan__SHIFT 0x2 +#define DF_CS_UMC_AON0_DramBaseAddress0__IntLvAddrSel__SHIFT 0x9 #define DF_CS_UMC_AON0_DramBaseAddress0__DramBaseAddr__SHIFT 0xc #define DF_CS_UMC_AON0_DramBaseAddress0__AddrRngVal_MASK 0x00000001L #define DF_CS_UMC_AON0_DramBaseAddress0__LgcyMmioHoleEn_MASK 0x00000002L -#define DF_CS_UMC_AON0_DramBaseAddress0__IntLvNumChan_MASK 0x000000F0L -#define DF_CS_UMC_AON0_DramBaseAddress0__IntLvAddrSel_MASK 0x00000700L +#define DF_CS_UMC_AON0_DramBaseAddress0__IntLvNumChan_MASK 0x0000003CL +#define DF_CS_UMC_AON0_DramBaseAddress0__IntLvAddrSel_MASK 0x00000E00L #define DF_CS_UMC_AON0_DramBaseAddress0__DramBaseAddr_MASK 0xFFFFF000L #endif diff --git a/drivers/gpu/drm/amd/include/atomfirmware.h b/drivers/gpu/drm/amd/include/atomfirmware.h index c6c1666ac120..092d800b703a 100644 --- a/drivers/gpu/drm/amd/include/atomfirmware.h +++ b/drivers/gpu/drm/amd/include/atomfirmware.h @@ -2026,17 +2026,15 @@ enum atom_smu11_syspll_id { SMU11_SYSPLL3_1_ID = 6, }; - enum atom_smu11_syspll0_clock_id { - SMU11_SYSPLL0_SOCCLK_ID = 0, // SOCCLK - SMU11_SYSPLL0_MP0CLK_ID = 1, // MP0CLK - SMU11_SYSPLL0_DCLK_ID = 2, // DCLK - SMU11_SYSPLL0_VCLK_ID = 3, // VCLK - SMU11_SYSPLL0_ECLK_ID = 4, // ECLK + SMU11_SYSPLL0_ECLK_ID = 0, // ECLK + SMU11_SYSPLL0_SOCCLK_ID = 1, // SOCCLK + SMU11_SYSPLL0_MP0CLK_ID = 2, // MP0CLK + SMU11_SYSPLL0_DCLK_ID = 3, // DCLK + SMU11_SYSPLL0_VCLK_ID = 4, // VCLK SMU11_SYSPLL0_DCEFCLK_ID = 5, // DCEFCLK }; - enum atom_smu11_syspll1_0_clock_id { SMU11_SYSPLL1_0_UCLKA_ID = 0, // UCLK_a }; diff --git a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c index b493369e6d0f..d567be49c31b 100644 --- a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c +++ b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c @@ -180,7 +180,6 @@ static int pp_late_init(void *handle) { struct amdgpu_device *adev = handle; struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; - int ret; if (hwmgr && hwmgr->pm_en) { mutex_lock(&hwmgr->smu_lock); @@ -191,13 +190,6 @@ static int pp_late_init(void *handle) if (adev->pm.smu_prv_buffer_size != 0) pp_reserve_vram_for_smu(adev); - if (hwmgr->hwmgr_func->gfx_off_control && - (hwmgr->feature_mask & PP_GFXOFF_MASK)) { - ret = hwmgr->hwmgr_func->gfx_off_control(hwmgr, true); - if (ret) - pr_err("gfx off enabling failed!\n"); - } - return 0; } @@ -245,7 +237,7 @@ static int pp_set_powergating_state(void *handle, } if (hwmgr->hwmgr_func->enable_per_cu_power_gating == NULL) { - pr_info("%s was not implemented.\n", __func__); + pr_debug("%s was not implemented.\n", __func__); return 0; } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.c b/drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.c index 0af13c154328..91ffb7bc4ee7 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.c @@ -50,7 +50,7 @@ int psm_init_power_state_table(struct pp_hwmgr *hwmgr) return 0; } - hwmgr->ps = kzalloc(size * table_entries, GFP_KERNEL); + hwmgr->ps = kcalloc(table_entries, size, GFP_KERNEL); if (hwmgr->ps == NULL) return -ENOMEM; @@ -265,19 +265,18 @@ int psm_adjust_power_state_dynamic(struct pp_hwmgr *hwmgr, bool skip, if (skip) return 0; - if (!hwmgr->ps) - /* - * for vega12/vega20 which does not support power state manager - * DAL clock limits should also be honoured - */ - phm_apply_clock_adjust_rules(hwmgr); - phm_pre_display_configuration_changed(hwmgr); phm_display_configuration_changed(hwmgr); if (hwmgr->ps) power_state_management(hwmgr, new_ps); + else + /* + * for vega12/vega20 which does not support power state manager + * DAL clock limits should also be honoured + */ + phm_apply_clock_adjust_rules(hwmgr); phm_notify_smc_display_config_after_ps_adjustment(hwmgr); diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomfwctrl.c b/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomfwctrl.c index c97b0e5ba43b..5325661fedff 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomfwctrl.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomfwctrl.c @@ -496,7 +496,9 @@ int pp_atomfwctrl_get_clk_information_by_clkid(struct pp_hwmgr *hwmgr, BIOS_CLKI uint32_t ix; parameters.clk_id = id; + parameters.syspll_id = 0; parameters.command = GET_SMU_CLOCK_INFO_V3_1_GET_CLOCK_FREQ; + parameters.dfsdid = 0; ix = GetIndexIntoMasterCmdTable(getsmuclockinfo); @@ -505,7 +507,7 @@ int pp_atomfwctrl_get_clk_information_by_clkid(struct pp_hwmgr *hwmgr, BIOS_CLKI return -EINVAL; output = (struct atom_get_smu_clock_info_output_parameters_v3_1 *)¶meters; - *frequency = output->atom_smu_outputclkfreq.smu_clock_freq_hz / 10000; + *frequency = le32_to_cpu(output->atom_smu_outputclkfreq.smu_clock_freq_hz) / 10000; return 0; } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c b/drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c index f0d48b183d22..35bd9870ab10 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c @@ -870,12 +870,6 @@ static int init_over_drive_limits( hwmgr->platform_descriptor.maxOverdriveVDDC = 0; hwmgr->platform_descriptor.overdriveVDDCStep = 0; - if (hwmgr->platform_descriptor.overdriveLimit.engineClock == 0 \ - || hwmgr->platform_descriptor.overdriveLimit.memoryClock == 0) { - hwmgr->od_enabled = false; - pr_debug("OverDrive feature not support by VBIOS\n"); - } - return 0; } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/processpptables.c b/drivers/gpu/drm/amd/powerplay/hwmgr/processpptables.c index ce64dfabd34b..925e17104f90 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/processpptables.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/processpptables.c @@ -1074,12 +1074,6 @@ static int init_overdrive_limits(struct pp_hwmgr *hwmgr, powerplay_table, (const ATOM_FIRMWARE_INFO_V2_1 *)fw_info); - if (hwmgr->platform_descriptor.overdriveLimit.engineClock == 0 - && hwmgr->platform_descriptor.overdriveLimit.memoryClock == 0) { - hwmgr->od_enabled = false; - pr_debug("OverDrive feature not support by VBIOS\n"); - } - return result; } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c index 85f84f4d8be5..d4bc83e81389 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c @@ -53,8 +53,37 @@ static const unsigned long SMU10_Magic = (unsigned long) PHM_Rv_Magic; static int smu10_display_clock_voltage_request(struct pp_hwmgr *hwmgr, - struct pp_display_clock_request *clock_req); + struct pp_display_clock_request *clock_req) +{ + struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend); + enum amd_pp_clock_type clk_type = clock_req->clock_type; + uint32_t clk_freq = clock_req->clock_freq_in_khz / 1000; + PPSMC_Msg msg; + switch (clk_type) { + case amd_pp_dcf_clock: + if (clk_freq == smu10_data->dcf_actual_hard_min_freq) + return 0; + msg = PPSMC_MSG_SetHardMinDcefclkByFreq; + smu10_data->dcf_actual_hard_min_freq = clk_freq; + break; + case amd_pp_soc_clock: + msg = PPSMC_MSG_SetHardMinSocclkByFreq; + break; + case amd_pp_f_clock: + if (clk_freq == smu10_data->f_actual_hard_min_freq) + return 0; + smu10_data->f_actual_hard_min_freq = clk_freq; + msg = PPSMC_MSG_SetHardMinFclkByFreq; + break; + default: + pr_info("[DisplayClockVoltageRequest]Invalid Clock Type!"); + return -EINVAL; + } + smum_send_msg_to_smc_with_parameter(hwmgr, msg, clk_freq); + + return 0; +} static struct smu10_power_state *cast_smu10_ps(struct pp_hw_power_state *hw_ps) { @@ -284,7 +313,7 @@ static int smu10_disable_gfx_off(struct pp_hwmgr *hwmgr) static int smu10_disable_dpm_tasks(struct pp_hwmgr *hwmgr) { - return smu10_disable_gfx_off(hwmgr); + return 0; } static int smu10_enable_gfx_off(struct pp_hwmgr *hwmgr) @@ -299,7 +328,7 @@ static int smu10_enable_gfx_off(struct pp_hwmgr *hwmgr) static int smu10_enable_dpm_tasks(struct pp_hwmgr *hwmgr) { - return smu10_enable_gfx_off(hwmgr); + return 0; } static int smu10_gfx_off_control(struct pp_hwmgr *hwmgr, bool enable) @@ -1000,6 +1029,12 @@ static int smu10_get_clock_by_type_with_voltage(struct pp_hwmgr *hwmgr, case amd_pp_soc_clock: pclk_vol_table = pinfo->vdd_dep_on_socclk; break; + case amd_pp_disp_clock: + pclk_vol_table = pinfo->vdd_dep_on_dispclk; + break; + case amd_pp_phy_clock: + pclk_vol_table = pinfo->vdd_dep_on_phyclk; + break; default: return -EINVAL; } @@ -1017,39 +1052,7 @@ static int smu10_get_clock_by_type_with_voltage(struct pp_hwmgr *hwmgr, return 0; } -static int smu10_display_clock_voltage_request(struct pp_hwmgr *hwmgr, - struct pp_display_clock_request *clock_req) -{ - struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend); - enum amd_pp_clock_type clk_type = clock_req->clock_type; - uint32_t clk_freq = clock_req->clock_freq_in_khz / 1000; - PPSMC_Msg msg; - switch (clk_type) { - case amd_pp_dcf_clock: - if (clk_freq == smu10_data->dcf_actual_hard_min_freq) - return 0; - msg = PPSMC_MSG_SetHardMinDcefclkByFreq; - smu10_data->dcf_actual_hard_min_freq = clk_freq; - break; - case amd_pp_soc_clock: - msg = PPSMC_MSG_SetHardMinSocclkByFreq; - break; - case amd_pp_f_clock: - if (clk_freq == smu10_data->f_actual_hard_min_freq) - return 0; - smu10_data->f_actual_hard_min_freq = clk_freq; - msg = PPSMC_MSG_SetHardMinFclkByFreq; - break; - default: - pr_info("[DisplayClockVoltageRequest]Invalid Clock Type!"); - return -EINVAL; - } - - smum_send_msg_to_smc_with_parameter(hwmgr, msg, clk_freq); - - return 0; -} static int smu10_get_max_high_clocks(struct pp_hwmgr *hwmgr, struct amd_pp_simple_clock_info *clocks) { @@ -1182,6 +1185,7 @@ static const struct pp_hwmgr_func smu10_hwmgr_funcs = { .set_mmhub_powergating_by_smu = smu10_set_mmhub_powergating_by_smu, .smus_notify_pwe = smu10_smus_notify_pwe, .gfx_off_control = smu10_gfx_off_control, + .display_clock_voltage_request = smu10_display_clock_voltage_request, }; int smu10_init_function_pointers(struct pp_hwmgr *hwmgr) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c index 45e9b8cb169d..f8e866ceda02 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c @@ -791,7 +791,8 @@ static int smu7_setup_dpm_tables_v1(struct pp_hwmgr *hwmgr) data->dpm_table.sclk_table.count++; } } - + if (hwmgr->platform_descriptor.overdriveLimit.engineClock == 0) + hwmgr->platform_descriptor.overdriveLimit.engineClock = dep_sclk_table->entries[i-1].clk; /* Initialize Mclk DPM table based on allow Mclk values */ data->dpm_table.mclk_table.count = 0; for (i = 0; i < dep_mclk_table->count; i++) { @@ -806,6 +807,8 @@ static int smu7_setup_dpm_tables_v1(struct pp_hwmgr *hwmgr) } } + if (hwmgr->platform_descriptor.overdriveLimit.memoryClock == 0) + hwmgr->platform_descriptor.overdriveLimit.memoryClock = dep_mclk_table->entries[i-1].clk; return 0; } @@ -3752,14 +3755,17 @@ static int smu7_trim_dpm_states(struct pp_hwmgr *hwmgr, static int smu7_generate_dpm_level_enable_mask( struct pp_hwmgr *hwmgr, const void *input) { - int result; + int result = 0; const struct phm_set_power_state_input *states = (const struct phm_set_power_state_input *)input; struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); const struct smu7_power_state *smu7_ps = cast_const_phw_smu7_power_state(states->pnew_state); - result = smu7_trim_dpm_states(hwmgr, smu7_ps); + /*skip the trim if od is enabled*/ + if (!hwmgr->od_enabled) + result = smu7_trim_dpm_states(hwmgr, smu7_ps); + if (result) return result; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c index d156b7bb92ae..05e680d55dbb 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c @@ -321,8 +321,12 @@ static int vega10_odn_initial_default_setting(struct pp_hwmgr *hwmgr) odn_table->min_vddc = dep_table[0]->entries[0].vddc; i = od_table[2]->count - 1; - od_table[2]->entries[i].clk = hwmgr->platform_descriptor.overdriveLimit.memoryClock; - od_table[2]->entries[i].vddc = odn_table->max_vddc; + od_table[2]->entries[i].clk = hwmgr->platform_descriptor.overdriveLimit.memoryClock > od_table[2]->entries[i].clk ? + hwmgr->platform_descriptor.overdriveLimit.memoryClock : + od_table[2]->entries[i].clk; + od_table[2]->entries[i].vddc = odn_table->max_vddc > od_table[2]->entries[i].vddc ? + odn_table->max_vddc : + od_table[2]->entries[i].vddc; return 0; } @@ -1311,6 +1315,9 @@ static int vega10_setup_default_dpm_tables(struct pp_hwmgr *hwmgr) vega10_setup_default_single_dpm_table(hwmgr, dpm_table, dep_gfx_table); + if (hwmgr->platform_descriptor.overdriveLimit.engineClock == 0) + hwmgr->platform_descriptor.overdriveLimit.engineClock = + dpm_table->dpm_levels[dpm_table->count-1].value; vega10_init_dpm_state(&(dpm_table->dpm_state)); /* Initialize Mclk DPM table based on allow Mclk values */ @@ -1319,6 +1326,10 @@ static int vega10_setup_default_dpm_tables(struct pp_hwmgr *hwmgr) vega10_setup_default_single_dpm_table(hwmgr, dpm_table, dep_mclk_table); + if (hwmgr->platform_descriptor.overdriveLimit.memoryClock == 0) + hwmgr->platform_descriptor.overdriveLimit.memoryClock = + dpm_table->dpm_levels[dpm_table->count-1].value; + vega10_init_dpm_state(&(dpm_table->dpm_state)); data->dpm_table.eclk_table.count = 0; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c index a9efd8554fbc..dbe4b1f66784 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c @@ -1104,7 +1104,7 @@ static int vega10_enable_psm_gc_edc_config(struct pp_hwmgr *hwmgr) for (count = 0; count < num_se; count++) { data = GRBM_GFX_INDEX__INSTANCE_BROADCAST_WRITES_MASK | GRBM_GFX_INDEX__SH_BROADCAST_WRITES_MASK | ( count << GRBM_GFX_INDEX__SE_INDEX__SHIFT); WREG32_SOC15(GC, 0, mmGRBM_GFX_INDEX, data); - result |= vega10_program_didt_config_registers(hwmgr, PSMSEEDCStallPatternConfig_Vega10, VEGA10_CONFIGREG_DIDT); + result = vega10_program_didt_config_registers(hwmgr, PSMSEEDCStallPatternConfig_Vega10, VEGA10_CONFIGREG_DIDT); result |= vega10_program_didt_config_registers(hwmgr, PSMSEEDCStallDelayConfig_Vega10, VEGA10_CONFIGREG_DIDT); result |= vega10_program_didt_config_registers(hwmgr, PSMSEEDCCtrlResetConfig_Vega10, VEGA10_CONFIGREG_DIDT); result |= vega10_program_didt_config_registers(hwmgr, PSMSEEDCCtrlConfig_Vega10, VEGA10_CONFIGREG_DIDT); diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_processpptables.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_processpptables.c index 0768d259c07c..16b1a9cf6cf0 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_processpptables.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_processpptables.c @@ -267,12 +267,6 @@ static int init_over_drive_limits( hwmgr->platform_descriptor.maxOverdriveVDDC = 0; hwmgr->platform_descriptor.overdriveVDDCStep = 0; - if (hwmgr->platform_descriptor.overdriveLimit.engineClock == 0 || - hwmgr->platform_descriptor.overdriveLimit.memoryClock == 0) { - hwmgr->od_enabled = false; - pr_debug("OverDrive feature not support by VBIOS\n"); - } - return 0; } diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 40e1e24f2ff0..a5808382bdf0 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1633,7 +1633,8 @@ struct edid *drm_do_get_edid(struct drm_connector *connector, edid[EDID_LENGTH-1] += edid[0x7e] - valid_extensions; edid[0x7e] = valid_extensions; - new = kmalloc((valid_extensions + 1) * EDID_LENGTH, GFP_KERNEL); + new = kmalloc_array(valid_extensions + 1, EDID_LENGTH, + GFP_KERNEL); if (!new) goto out; diff --git a/drivers/gpu/drm/drm_hashtab.c b/drivers/gpu/drm/drm_hashtab.c index dae18e58e79b..c92b00d42ece 100644 --- a/drivers/gpu/drm/drm_hashtab.c +++ b/drivers/gpu/drm/drm_hashtab.c @@ -47,7 +47,7 @@ int drm_ht_create(struct drm_open_hash *ht, unsigned int order) if (size <= PAGE_SIZE / sizeof(*ht->table)) ht->table = kcalloc(size, sizeof(*ht->table), GFP_KERNEL); else - ht->table = vzalloc(size*sizeof(*ht->table)); + ht->table = vzalloc(array_size(size, sizeof(*ht->table))); if (!ht->table) { DRM_ERROR("Out of memory for hash table\n"); return -ENOMEM; diff --git a/drivers/gpu/drm/drm_memory.c b/drivers/gpu/drm/drm_memory.c index 3c54044214db..d69e4fc1ee77 100644 --- a/drivers/gpu/drm/drm_memory.c +++ b/drivers/gpu/drm/drm_memory.c @@ -80,7 +80,7 @@ static void *agp_remap(unsigned long offset, unsigned long size, * page-table instead (that's probably faster anyhow...). */ /* note: use vmalloc() because num_pages could be large... */ - page_map = vmalloc(num_pages * sizeof(struct page *)); + page_map = vmalloc(array_size(num_pages, sizeof(struct page *))); if (!page_map) return NULL; diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 7c3030b7e586..6d29777884f9 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1723,8 +1723,8 @@ static int exynos_dsi_probe(struct platform_device *pdev) return -EPROBE_DEFER; } - dsi->clks = devm_kzalloc(dev, - sizeof(*dsi->clks) * dsi->driver_data->num_clks, + dsi->clks = devm_kcalloc(dev, + dsi->driver_data->num_clks, sizeof(*dsi->clks), GFP_KERNEL); if (!dsi->clks) return -ENOMEM; diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimc.c b/drivers/gpu/drm/exynos/exynos_drm_fimc.c index 5ce84025d1cb..6127ef25acd6 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimc.c @@ -1271,7 +1271,8 @@ static int fimc_probe(struct platform_device *pdev) /* construct formats/limits array */ num_formats = ARRAY_SIZE(fimc_formats) + ARRAY_SIZE(fimc_tiled_formats); - formats = devm_kzalloc(dev, sizeof(*formats) * num_formats, GFP_KERNEL); + formats = devm_kcalloc(dev, num_formats, sizeof(*formats), + GFP_KERNEL); if (!formats) return -ENOMEM; diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c index e99dd1e4ba65..35ac66730563 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c @@ -1202,8 +1202,9 @@ static int gsc_probe(struct platform_device *pdev) if (!ctx) return -ENOMEM; - formats = devm_kzalloc(dev, sizeof(*formats) * - (ARRAY_SIZE(gsc_formats)), GFP_KERNEL); + formats = devm_kcalloc(dev, + ARRAY_SIZE(gsc_formats), sizeof(*formats), + GFP_KERNEL); if (!formats) return -ENOMEM; diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 09c4bc0b1859..db91932550cf 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -1692,7 +1692,7 @@ static int hdmi_clk_init(struct hdmi_context *hdata) if (!count) return 0; - clks = devm_kzalloc(dev, sizeof(*clks) * count, GFP_KERNEL); + clks = devm_kcalloc(dev, count, sizeof(*clks), GFP_KERNEL); if (!clks) return -ENOMEM; diff --git a/drivers/gpu/drm/gma500/mid_bios.c b/drivers/gpu/drm/gma500/mid_bios.c index 7171b7475f58..237041a37532 100644 --- a/drivers/gpu/drm/gma500/mid_bios.c +++ b/drivers/gpu/drm/gma500/mid_bios.c @@ -239,7 +239,7 @@ static int mid_get_vbt_data_r10(struct drm_psb_private *dev_priv, u32 addr) if (read_vbt_r10(addr, &vbt)) return -1; - gct = kmalloc(sizeof(*gct) * vbt.panel_count, GFP_KERNEL); + gct = kmalloc_array(vbt.panel_count, sizeof(*gct), GFP_KERNEL); if (!gct) return -ENOMEM; diff --git a/drivers/gpu/drm/i915/gvt/cmd_parser.c b/drivers/gpu/drm/i915/gvt/cmd_parser.c index 718ca08f9575..b51c05d03f14 100644 --- a/drivers/gpu/drm/i915/gvt/cmd_parser.c +++ b/drivers/gpu/drm/i915/gvt/cmd_parser.c @@ -2909,6 +2909,7 @@ static int init_cmd_table(struct intel_gvt *gvt) if (info) { gvt_err("%s %s duplicated\n", e->info->name, info->name); + kfree(e); return -EEXIST; } diff --git a/drivers/gpu/drm/i915/gvt/display.h b/drivers/gpu/drm/i915/gvt/display.h index b46b86892d58..ea7c1c525b8c 100644 --- a/drivers/gpu/drm/i915/gvt/display.h +++ b/drivers/gpu/drm/i915/gvt/display.h @@ -67,7 +67,7 @@ #define AUX_NATIVE_REPLY_NAK (0x1 << 4) #define AUX_NATIVE_REPLY_DEFER (0x2 << 4) -#define AUX_BURST_SIZE 16 +#define AUX_BURST_SIZE 20 /* DPCD addresses */ #define DPCD_REV 0x000 diff --git a/drivers/gpu/drm/i915/gvt/gtt.c b/drivers/gpu/drm/i915/gvt/gtt.c index 78e55aafc8bc..23296547da95 100644 --- a/drivers/gpu/drm/i915/gvt/gtt.c +++ b/drivers/gpu/drm/i915/gvt/gtt.c @@ -1585,8 +1585,9 @@ static struct intel_vgpu_mm *intel_vgpu_create_ggtt_mm(struct intel_vgpu *vgpu) mm->type = INTEL_GVT_MM_GGTT; nr_entries = gvt_ggtt_gm_sz(vgpu->gvt) >> I915_GTT_PAGE_SHIFT; - mm->ggtt_mm.virtual_ggtt = vzalloc(nr_entries * - vgpu->gvt->device_info.gtt_entry_size); + mm->ggtt_mm.virtual_ggtt = + vzalloc(array_size(nr_entries, + vgpu->gvt->device_info.gtt_entry_size)); if (!mm->ggtt_mm.virtual_ggtt) { vgpu_free_mm(mm); return ERR_PTR(-ENOMEM); diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c index 4b6532fb789a..bcbc47a88a70 100644 --- a/drivers/gpu/drm/i915/gvt/handlers.c +++ b/drivers/gpu/drm/i915/gvt/handlers.c @@ -903,11 +903,14 @@ static int dp_aux_ch_ctl_mmio_write(struct intel_vgpu *vgpu, } /* - * Write request format: (command + address) occupies - * 3 bytes, followed by (len + 1) bytes of data. + * Write request format: Headr (command + address + size) occupies + * 4 bytes, followed by (len + 1) bytes of data. See details at + * intel_dp_aux_transfer(). */ - if (WARN_ON((len + 4) > AUX_BURST_SIZE)) + if ((len + 1 + 4) > AUX_BURST_SIZE) { + gvt_vgpu_err("dp_aux_header: len %d is too large\n", len); return -EINVAL; + } /* unpack data from vreg to buf */ for (t = 0; t < 4; t++) { @@ -971,8 +974,10 @@ static int dp_aux_ch_ctl_mmio_write(struct intel_vgpu *vgpu, /* * Read reply format: ACK (1 byte) plus (len + 1) bytes of data. */ - if (WARN_ON((len + 2) > AUX_BURST_SIZE)) + if ((len + 2) > AUX_BURST_SIZE) { + gvt_vgpu_err("dp_aux_header: len %d is too large\n", len); return -EINVAL; + } /* read from virtual DPCD to vreg */ /* first 4 bytes: [ACK][addr][addr+1][addr+2] */ diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c index 1466d8769ec9..df4e4a07db3d 100644 --- a/drivers/gpu/drm/i915/gvt/kvmgt.c +++ b/drivers/gpu/drm/i915/gvt/kvmgt.c @@ -123,6 +123,12 @@ static int gvt_dma_map_page(struct intel_vgpu *vgpu, unsigned long gfn, return -EINVAL; } + if (!pfn_valid(pfn)) { + gvt_vgpu_err("pfn 0x%lx is not mem backed\n", pfn); + vfio_unpin_pages(mdev_dev(vgpu->vdev.mdev), &gfn, 1); + return -EINVAL; + } + /* Setup DMA mapping. */ page = pfn_to_page(pfn); *dma_addr = dma_map_page(dev, page, 0, PAGE_SIZE, @@ -583,6 +589,17 @@ out: return ret; } +static void intel_vgpu_release_msi_eventfd_ctx(struct intel_vgpu *vgpu) +{ + struct eventfd_ctx *trigger; + + trigger = vgpu->vdev.msi_trigger; + if (trigger) { + eventfd_ctx_put(trigger); + vgpu->vdev.msi_trigger = NULL; + } +} + static void __intel_vgpu_release(struct intel_vgpu *vgpu) { struct kvmgt_guest_info *info; @@ -607,6 +624,8 @@ static void __intel_vgpu_release(struct intel_vgpu *vgpu) info = (struct kvmgt_guest_info *)vgpu->handle; kvmgt_guest_exit(info); + intel_vgpu_release_msi_eventfd_ctx(vgpu); + vgpu->vdev.kvm = NULL; vgpu->handle = 0; } @@ -987,7 +1006,8 @@ static int intel_vgpu_set_msi_trigger(struct intel_vgpu *vgpu, return PTR_ERR(trigger); } vgpu->vdev.msi_trigger = trigger; - } + } else if ((flags & VFIO_IRQ_SET_DATA_NONE) && !count) + intel_vgpu_release_msi_eventfd_ctx(vgpu); return 0; } @@ -1592,6 +1612,18 @@ static int kvmgt_inject_msi(unsigned long handle, u32 addr, u16 data) info = (struct kvmgt_guest_info *)handle; vgpu = info->vgpu; + /* + * When guest is poweroff, msi_trigger is set to NULL, but vgpu's + * config and mmio register isn't restored to default during guest + * poweroff. If this vgpu is still used in next vm, this vgpu's pipe + * may be enabled, then once this vgpu is active, it will get inject + * vblank interrupt request. But msi_trigger is null until msi is + * enabled by guest. so if msi_trigger is null, success is still + * returned and don't inject interrupt into guest. + */ + if (vgpu->vdev.msi_trigger == NULL) + return 0; + if (eventfd_signal(vgpu->vdev.msi_trigger, 1) == 1) return 0; diff --git a/drivers/gpu/drm/i915/gvt/mmio.c b/drivers/gpu/drm/i915/gvt/mmio.c index e4960aff68bd..b31eb36fc102 100644 --- a/drivers/gpu/drm/i915/gvt/mmio.c +++ b/drivers/gpu/drm/i915/gvt/mmio.c @@ -267,7 +267,7 @@ int intel_vgpu_init_mmio(struct intel_vgpu *vgpu) { const struct intel_gvt_device_info *info = &vgpu->gvt->device_info; - vgpu->mmio.vreg = vzalloc(info->mmio_size * 2); + vgpu->mmio.vreg = vzalloc(array_size(info->mmio_size, 2)); if (!vgpu->mmio.vreg) return -ENOMEM; diff --git a/drivers/gpu/drm/i915/gvt/vgpu.c b/drivers/gpu/drm/i915/gvt/vgpu.c index 2e0a02a80fe4..572a18c2bfb5 100644 --- a/drivers/gpu/drm/i915/gvt/vgpu.c +++ b/drivers/gpu/drm/i915/gvt/vgpu.c @@ -121,7 +121,7 @@ int intel_gvt_init_vgpu_types(struct intel_gvt *gvt) high_avail = gvt_hidden_sz(gvt) - HOST_HIGH_GM_SIZE; num_types = sizeof(vgpu_types) / sizeof(vgpu_types[0]); - gvt->types = kzalloc(num_types * sizeof(struct intel_vgpu_type), + gvt->types = kcalloc(num_types, sizeof(struct intel_vgpu_type), GFP_KERNEL); if (!gvt->types) return -ENOMEM; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 0a2070112b66..3704f4c0c2c9 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2972,23 +2972,22 @@ i915_gem_find_active_request(struct intel_engine_cs *engine) struct i915_request *request, *active = NULL; unsigned long flags; - /* We are called by the error capture and reset at a random - * point in time. In particular, note that neither is crucially - * ordered with an interrupt. After a hang, the GPU is dead and we - * assume that no more writes can happen (we waited long enough for - * all writes that were in transaction to be flushed) - adding an + /* + * We are called by the error capture, reset and to dump engine + * state at random points in time. In particular, note that neither is + * crucially ordered with an interrupt. After a hang, the GPU is dead + * and we assume that no more writes can happen (we waited long enough + * for all writes that were in transaction to be flushed) - adding an * extra delay for a recent interrupt is pointless. Hence, we do * not need an engine->irq_seqno_barrier() before the seqno reads. + * At all other times, we must assume the GPU is still running, but + * we only care about the snapshot of this moment. */ spin_lock_irqsave(&engine->timeline.lock, flags); list_for_each_entry(request, &engine->timeline.requests, link) { if (__i915_request_completed(request, request->global_seqno)) continue; - GEM_BUG_ON(request->engine != engine); - GEM_BUG_ON(test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, - &request->fence.flags)); - active = request; break; } diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index b98ac0541f19..f4a8598a2d39 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -2453,12 +2453,13 @@ void icl_map_plls_to_ports(struct drm_crtc *crtc, for_each_new_connector_in_state(old_state, conn, conn_state, i) { struct intel_encoder *encoder = to_intel_encoder(conn_state->best_encoder); - enum port port = encoder->port; + enum port port; uint32_t val; if (conn_state->crtc != crtc) continue; + port = encoder->port; mutex_lock(&dev_priv->dpll_lock); val = I915_READ(DPCLKA_CFGCR0_ICL); @@ -2490,11 +2491,12 @@ void icl_unmap_plls_to_ports(struct drm_crtc *crtc, for_each_old_connector_in_state(old_state, conn, old_conn_state, i) { struct intel_encoder *encoder = to_intel_encoder(old_conn_state->best_encoder); - enum port port = encoder->port; + enum port port; if (old_conn_state->crtc != crtc) continue; + port = encoder->port; mutex_lock(&dev_priv->dpll_lock); I915_WRITE(DPCLKA_CFGCR0_ICL, I915_READ(DPCLKA_CFGCR0_ICL) | diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ad588d564198..dee3a8e659f1 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3690,11 +3690,6 @@ u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state, plane_color_ctl |= glk_plane_color_ctl_alpha(fb->format->format); if (intel_format_is_yuv(fb->format->format)) { - if (fb->format->format == DRM_FORMAT_NV12) { - plane_color_ctl |= - PLANE_COLOR_CSC_MODE_YUV709_TO_RGB709; - goto out; - } if (plane_state->base.color_encoding == DRM_COLOR_YCBCR_BT709) plane_color_ctl |= PLANE_COLOR_CSC_MODE_YUV709_TO_RGB709; else @@ -3703,7 +3698,7 @@ u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state, if (plane_state->base.color_range == DRM_COLOR_YCBCR_FULL_RANGE) plane_color_ctl |= PLANE_COLOR_YUV_RANGE_CORRECTION_DISABLE; } -out: + return plane_color_ctl; } diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index dde92e4af5d3..8320f0e8e3be 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1679,23 +1679,6 @@ static int intel_dp_compute_bpp(struct intel_dp *intel_dp, return bpp; } -static bool intel_edp_compare_alt_mode(struct drm_display_mode *m1, - struct drm_display_mode *m2) -{ - bool bres = false; - - if (m1 && m2) - bres = (m1->hdisplay == m2->hdisplay && - m1->hsync_start == m2->hsync_start && - m1->hsync_end == m2->hsync_end && - m1->htotal == m2->htotal && - m1->vdisplay == m2->vdisplay && - m1->vsync_start == m2->vsync_start && - m1->vsync_end == m2->vsync_end && - m1->vtotal == m2->vtotal); - return bres; -} - /* Adjust link config limits based on compliance test requests. */ static void intel_dp_adjust_compliance_config(struct intel_dp *intel_dp, @@ -1860,16 +1843,8 @@ intel_dp_compute_config(struct intel_encoder *encoder, pipe_config->has_audio = intel_conn_state->force_audio == HDMI_AUDIO_ON; if (intel_dp_is_edp(intel_dp) && intel_connector->panel.fixed_mode) { - struct drm_display_mode *panel_mode = - intel_connector->panel.alt_fixed_mode; - struct drm_display_mode *req_mode = &pipe_config->base.mode; - - if (!intel_edp_compare_alt_mode(req_mode, panel_mode)) - panel_mode = intel_connector->panel.fixed_mode; - - drm_mode_debug_printmodeline(panel_mode); - - intel_fixed_panel_mode(panel_mode, adjusted_mode); + intel_fixed_panel_mode(intel_connector->panel.fixed_mode, + adjusted_mode); if (INTEL_GEN(dev_priv) >= 9) { int ret; @@ -6159,7 +6134,6 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, struct drm_i915_private *dev_priv = to_i915(dev); struct drm_connector *connector = &intel_connector->base; struct drm_display_mode *fixed_mode = NULL; - struct drm_display_mode *alt_fixed_mode = NULL; struct drm_display_mode *downclock_mode = NULL; bool has_dpcd; struct drm_display_mode *scan; @@ -6214,14 +6188,13 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, } intel_connector->edid = edid; - /* prefer fixed mode from EDID if available, save an alt mode also */ + /* prefer fixed mode from EDID if available */ list_for_each_entry(scan, &connector->probed_modes, head) { if ((scan->type & DRM_MODE_TYPE_PREFERRED)) { fixed_mode = drm_mode_duplicate(dev, scan); downclock_mode = intel_dp_drrs_init( intel_connector, fixed_mode); - } else if (!alt_fixed_mode) { - alt_fixed_mode = drm_mode_duplicate(dev, scan); + break; } } @@ -6258,8 +6231,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, pipe_name(pipe)); } - intel_panel_init(&intel_connector->panel, fixed_mode, alt_fixed_mode, - downclock_mode); + intel_panel_init(&intel_connector->panel, fixed_mode, downclock_mode); intel_connector->panel.backlight.power = intel_edp_backlight_power; intel_panel_setup_backlight(connector, pipe); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index d7dbca1aabff..0361130500a6 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -277,7 +277,6 @@ struct intel_encoder { struct intel_panel { struct drm_display_mode *fixed_mode; - struct drm_display_mode *alt_fixed_mode; struct drm_display_mode *downclock_mode; /* backlight */ @@ -1850,7 +1849,6 @@ void intel_overlay_reset(struct drm_i915_private *dev_priv); /* intel_panel.c */ int intel_panel_init(struct intel_panel *panel, struct drm_display_mode *fixed_mode, - struct drm_display_mode *alt_fixed_mode, struct drm_display_mode *downclock_mode); void intel_panel_fini(struct intel_panel *panel); void intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode, diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 51a1d6868b1e..cf39ca90d887 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -1846,7 +1846,7 @@ void intel_dsi_init(struct drm_i915_private *dev_priv) connector->display_info.width_mm = fixed_mode->width_mm; connector->display_info.height_mm = fixed_mode->height_mm; - intel_panel_init(&intel_connector->panel, fixed_mode, NULL, NULL); + intel_panel_init(&intel_connector->panel, fixed_mode, NULL); intel_panel_setup_backlight(connector, INVALID_PIPE); intel_dsi_add_properties(intel_connector); diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index eb0c559b2715..a70d767313aa 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -536,7 +536,7 @@ void intel_dvo_init(struct drm_i915_private *dev_priv) */ intel_panel_init(&intel_connector->panel, intel_dvo_get_current_mode(intel_encoder), - NULL, NULL); + NULL); intel_dvo->panel_wants_dither = true; } diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index 6bfd7e3ed152..1590375f31cb 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -1114,7 +1114,7 @@ static void print_request(struct drm_printer *m, const char *prefix) { const char *name = rq->fence.ops->get_timeline_name(&rq->fence); - char buf[80]; + char buf[80] = ""; int x = 0; x = print_sched_attr(rq->i915, &rq->sched.attr, buf, x, sizeof(buf)); diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index 2db5da550a1c..0cc6a861bcf8 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -429,7 +429,7 @@ int intel_hdcp_auth_downstream(struct intel_digital_port *intel_dig_port, if (num_downstream == 0) return -EINVAL; - ksv_fifo = kzalloc(num_downstream * DRM_HDCP_KSV_LEN, GFP_KERNEL); + ksv_fifo = kcalloc(DRM_HDCP_KSV_LEN, num_downstream, GFP_KERNEL); if (!ksv_fifo) return -ENOMEM; diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index e125d16a1aa7..d278f24ba6ae 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -1175,8 +1175,7 @@ void intel_lvds_init(struct drm_i915_private *dev_priv) out: mutex_unlock(&dev->mode_config.mutex); - intel_panel_init(&intel_connector->panel, fixed_mode, NULL, - downclock_mode); + intel_panel_init(&intel_connector->panel, fixed_mode, downclock_mode); intel_panel_setup_backlight(connector, INVALID_PIPE); lvds_encoder->is_dual_link = compute_is_dual_link_lvds(lvds_encoder); diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 41d00b1603e3..b443278e569c 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -1928,13 +1928,11 @@ intel_panel_init_backlight_funcs(struct intel_panel *panel) int intel_panel_init(struct intel_panel *panel, struct drm_display_mode *fixed_mode, - struct drm_display_mode *alt_fixed_mode, struct drm_display_mode *downclock_mode) { intel_panel_init_backlight_funcs(panel); panel->fixed_mode = fixed_mode; - panel->alt_fixed_mode = alt_fixed_mode; panel->downclock_mode = downclock_mode; return 0; @@ -1948,10 +1946,6 @@ void intel_panel_fini(struct intel_panel *panel) if (panel->fixed_mode) drm_mode_destroy(intel_connector->base.dev, panel->fixed_mode); - if (panel->alt_fixed_mode) - drm_mode_destroy(intel_connector->base.dev, - panel->alt_fixed_mode); - if (panel->downclock_mode) drm_mode_destroy(intel_connector->base.dev, panel->downclock_mode); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index b85229e153c4..53aaaa3e6886 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5150,7 +5150,6 @@ skl_copy_ddb_for_pipe(struct skl_ddb_values *dst, sizeof(dst->ddb.uv_plane[pipe])); memcpy(dst->ddb.plane[pipe], src->ddb.plane[pipe], sizeof(dst->ddb.plane[pipe])); - dst->ddb.enabled_slices = src->ddb.enabled_slices; } static void diff --git a/drivers/gpu/drm/i915/selftests/intel_uncore.c b/drivers/gpu/drm/i915/selftests/intel_uncore.c index f76f2597df5c..47bc5b2ddb56 100644 --- a/drivers/gpu/drm/i915/selftests/intel_uncore.c +++ b/drivers/gpu/drm/i915/selftests/intel_uncore.c @@ -137,7 +137,7 @@ static int intel_uncore_check_forcewake_domains(struct drm_i915_private *dev_pri if (!IS_ENABLED(CONFIG_DRM_I915_SELFTEST_BROKEN)) return 0; - valid = kzalloc(BITS_TO_LONGS(FW_RANGE) * sizeof(*valid), + valid = kcalloc(BITS_TO_LONGS(FW_RANGE), sizeof(*valid), GFP_KERNEL); if (!valid) return -ENOMEM; diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c index 7a1ad3af08e3..20e956e14c21 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c @@ -98,21 +98,6 @@ static const struct drm_plane_funcs mdp4_plane_funcs = { .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, }; -static int mdp4_plane_prepare_fb(struct drm_plane *plane, - struct drm_plane_state *new_state) -{ - struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane); - struct mdp4_kms *mdp4_kms = get_kms(plane); - struct msm_kms *kms = &mdp4_kms->base.base; - struct drm_framebuffer *fb = new_state->fb; - - if (!fb) - return 0; - - DBG("%s: prepare: FB[%u]", mdp4_plane->name, fb->base.id); - return msm_framebuffer_prepare(fb, kms->aspace); -} - static void mdp4_plane_cleanup_fb(struct drm_plane *plane, struct drm_plane_state *old_state) { @@ -152,7 +137,7 @@ static void mdp4_plane_atomic_update(struct drm_plane *plane, } static const struct drm_plane_helper_funcs mdp4_plane_helper_funcs = { - .prepare_fb = mdp4_plane_prepare_fb, + .prepare_fb = msm_atomic_prepare_fb, .cleanup_fb = mdp4_plane_cleanup_fb, .atomic_check = mdp4_plane_atomic_check, .atomic_update = mdp4_plane_atomic_update, diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c index 76b96081916f..10271359789e 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c @@ -430,6 +430,7 @@ static void mdp5_crtc_atomic_disable(struct drm_crtc *crtc, struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state); struct mdp5_kms *mdp5_kms = get_kms(crtc); struct device *dev = &mdp5_kms->pdev->dev; + unsigned long flags; DBG("%s", crtc->name); @@ -445,6 +446,14 @@ static void mdp5_crtc_atomic_disable(struct drm_crtc *crtc, mdp_irq_unregister(&mdp5_kms->base, &mdp5_crtc->err); pm_runtime_put_sync(dev); + if (crtc->state->event && !crtc->state->active) { + WARN_ON(mdp5_crtc->event); + spin_lock_irqsave(&mdp5_kms->dev->event_lock, flags); + drm_crtc_send_vblank_event(crtc, crtc->state->event); + crtc->state->event = NULL; + spin_unlock_irqrestore(&mdp5_kms->dev->event_lock, flags); + } + mdp5_crtc->enabled = false; } diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c index 6d8e3a9a6fc0..6e12e275deba 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c @@ -70,60 +70,110 @@ static int mdp5_hw_init(struct msm_kms *kms) return 0; } -struct mdp5_state *mdp5_get_state(struct drm_atomic_state *s) +/* Global/shared object state funcs */ + +/* + * This is a helper that returns the private state currently in operation. + * Note that this would return the "old_state" if called in the atomic check + * path, and the "new_state" after the atomic swap has been done. + */ +struct mdp5_global_state * +mdp5_get_existing_global_state(struct mdp5_kms *mdp5_kms) +{ + return to_mdp5_global_state(mdp5_kms->glob_state.state); +} + +/* + * This acquires the modeset lock set aside for global state, creates + * a new duplicated private object state. + */ +struct mdp5_global_state *mdp5_get_global_state(struct drm_atomic_state *s) { struct msm_drm_private *priv = s->dev->dev_private; struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms)); - struct msm_kms_state *state = to_kms_state(s); - struct mdp5_state *new_state; + struct drm_private_state *priv_state; int ret; - if (state->state) - return state->state; - - ret = drm_modeset_lock(&mdp5_kms->state_lock, s->acquire_ctx); + ret = drm_modeset_lock(&mdp5_kms->glob_state_lock, s->acquire_ctx); if (ret) return ERR_PTR(ret); - new_state = kmalloc(sizeof(*mdp5_kms->state), GFP_KERNEL); - if (!new_state) - return ERR_PTR(-ENOMEM); + priv_state = drm_atomic_get_private_obj_state(s, &mdp5_kms->glob_state); + if (IS_ERR(priv_state)) + return ERR_CAST(priv_state); - /* Copy state: */ - new_state->hwpipe = mdp5_kms->state->hwpipe; - new_state->hwmixer = mdp5_kms->state->hwmixer; - if (mdp5_kms->smp) - new_state->smp = mdp5_kms->state->smp; + return to_mdp5_global_state(priv_state); +} + +static struct drm_private_state * +mdp5_global_duplicate_state(struct drm_private_obj *obj) +{ + struct mdp5_global_state *state; + + state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL); + if (!state) + return NULL; - state->state = new_state; + __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base); - return new_state; + return &state->base; } -static void mdp5_swap_state(struct msm_kms *kms, struct drm_atomic_state *state) +static void mdp5_global_destroy_state(struct drm_private_obj *obj, + struct drm_private_state *state) { - struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); - swap(to_kms_state(state)->state, mdp5_kms->state); + struct mdp5_global_state *mdp5_state = to_mdp5_global_state(state); + + kfree(mdp5_state); +} + +static const struct drm_private_state_funcs mdp5_global_state_funcs = { + .atomic_duplicate_state = mdp5_global_duplicate_state, + .atomic_destroy_state = mdp5_global_destroy_state, +}; + +static int mdp5_global_obj_init(struct mdp5_kms *mdp5_kms) +{ + struct mdp5_global_state *state; + + drm_modeset_lock_init(&mdp5_kms->glob_state_lock); + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return -ENOMEM; + + state->mdp5_kms = mdp5_kms; + + drm_atomic_private_obj_init(&mdp5_kms->glob_state, + &state->base, + &mdp5_global_state_funcs); + return 0; } static void mdp5_prepare_commit(struct msm_kms *kms, struct drm_atomic_state *state) { struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); struct device *dev = &mdp5_kms->pdev->dev; + struct mdp5_global_state *global_state; + + global_state = mdp5_get_existing_global_state(mdp5_kms); pm_runtime_get_sync(dev); if (mdp5_kms->smp) - mdp5_smp_prepare_commit(mdp5_kms->smp, &mdp5_kms->state->smp); + mdp5_smp_prepare_commit(mdp5_kms->smp, &global_state->smp); } static void mdp5_complete_commit(struct msm_kms *kms, struct drm_atomic_state *state) { struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); struct device *dev = &mdp5_kms->pdev->dev; + struct mdp5_global_state *global_state; + + global_state = mdp5_get_existing_global_state(mdp5_kms); if (mdp5_kms->smp) - mdp5_smp_complete_commit(mdp5_kms->smp, &mdp5_kms->state->smp); + mdp5_smp_complete_commit(mdp5_kms->smp, &global_state->smp); pm_runtime_put_sync(dev); } @@ -229,7 +279,6 @@ static const struct mdp_kms_funcs kms_funcs = { .irq = mdp5_irq, .enable_vblank = mdp5_enable_vblank, .disable_vblank = mdp5_disable_vblank, - .swap_state = mdp5_swap_state, .prepare_commit = mdp5_prepare_commit, .complete_commit = mdp5_complete_commit, .wait_for_crtc_commit_done = mdp5_wait_for_crtc_commit_done, @@ -727,7 +776,8 @@ static void mdp5_destroy(struct platform_device *pdev) if (mdp5_kms->rpm_enabled) pm_runtime_disable(&pdev->dev); - kfree(mdp5_kms->state); + drm_atomic_private_obj_fini(&mdp5_kms->glob_state); + drm_modeset_lock_fini(&mdp5_kms->glob_state_lock); } static int construct_pipes(struct mdp5_kms *mdp5_kms, int cnt, @@ -880,12 +930,9 @@ static int mdp5_init(struct platform_device *pdev, struct drm_device *dev) mdp5_kms->dev = dev; mdp5_kms->pdev = pdev; - drm_modeset_lock_init(&mdp5_kms->state_lock); - mdp5_kms->state = kzalloc(sizeof(*mdp5_kms->state), GFP_KERNEL); - if (!mdp5_kms->state) { - ret = -ENOMEM; + ret = mdp5_global_obj_init(mdp5_kms); + if (ret) goto fail; - } mdp5_kms->mmio = msm_ioremap(pdev, "mdp_phys", "MDP5"); if (IS_ERR(mdp5_kms->mmio)) { diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.h index 425a03d213e5..854dfd30e829 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.h +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.h @@ -28,8 +28,6 @@ #include "mdp5_ctl.h" #include "mdp5_smp.h" -struct mdp5_state; - struct mdp5_kms { struct mdp_kms base; @@ -49,11 +47,12 @@ struct mdp5_kms { struct mdp5_cfg_handler *cfg; uint32_t caps; /* MDP capabilities (MDP_CAP_XXX bits) */ - /** - * Global atomic state. Do not access directly, use mdp5_get_state() + /* + * Global private object state, Do not access directly, use + * mdp5_global_get_state() */ - struct mdp5_state *state; - struct drm_modeset_lock state_lock; + struct drm_modeset_lock glob_state_lock; + struct drm_private_obj glob_state; struct mdp5_smp *smp; struct mdp5_ctl_manager *ctlm; @@ -81,19 +80,23 @@ struct mdp5_kms { }; #define to_mdp5_kms(x) container_of(x, struct mdp5_kms, base) -/* Global atomic state for tracking resources that are shared across +/* Global private object state for tracking resources that are shared across * multiple kms objects (planes/crtcs/etc). - * - * For atomic updates which require modifying global state, */ -struct mdp5_state { +#define to_mdp5_global_state(x) container_of(x, struct mdp5_global_state, base) +struct mdp5_global_state { + struct drm_private_state base; + + struct drm_atomic_state *state; + struct mdp5_kms *mdp5_kms; + struct mdp5_hw_pipe_state hwpipe; struct mdp5_hw_mixer_state hwmixer; struct mdp5_smp_state smp; }; -struct mdp5_state *__must_check -mdp5_get_state(struct drm_atomic_state *s); +struct mdp5_global_state * mdp5_get_existing_global_state(struct mdp5_kms *mdp5_kms); +struct mdp5_global_state *__must_check mdp5_get_global_state(struct drm_atomic_state *s); /* Atomic plane state. Subclasses the base drm_plane_state in order to * track assigned hwpipe and hw specific state. diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.c index 8a00991f03c7..113e6b569562 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.c @@ -52,14 +52,14 @@ int mdp5_mixer_assign(struct drm_atomic_state *s, struct drm_crtc *crtc, { struct msm_drm_private *priv = s->dev->dev_private; struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms)); - struct mdp5_state *state = mdp5_get_state(s); + struct mdp5_global_state *global_state = mdp5_get_global_state(s); struct mdp5_hw_mixer_state *new_state; int i; - if (IS_ERR(state)) - return PTR_ERR(state); + if (IS_ERR(global_state)) + return PTR_ERR(global_state); - new_state = &state->hwmixer; + new_state = &global_state->hwmixer; for (i = 0; i < mdp5_kms->num_hwmixers; i++) { struct mdp5_hw_mixer *cur = mdp5_kms->hwmixers[i]; @@ -129,8 +129,8 @@ int mdp5_mixer_assign(struct drm_atomic_state *s, struct drm_crtc *crtc, void mdp5_mixer_release(struct drm_atomic_state *s, struct mdp5_hw_mixer *mixer) { - struct mdp5_state *state = mdp5_get_state(s); - struct mdp5_hw_mixer_state *new_state = &state->hwmixer; + struct mdp5_global_state *global_state = mdp5_get_global_state(s); + struct mdp5_hw_mixer_state *new_state = &global_state->hwmixer; if (!mixer) return; diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.c index ff52c49095f9..1ef26bc63163 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.c @@ -24,17 +24,19 @@ int mdp5_pipe_assign(struct drm_atomic_state *s, struct drm_plane *plane, { struct msm_drm_private *priv = s->dev->dev_private; struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms)); - struct mdp5_state *state; + struct mdp5_global_state *new_global_state, *old_global_state; struct mdp5_hw_pipe_state *old_state, *new_state; int i, j; - state = mdp5_get_state(s); - if (IS_ERR(state)) - return PTR_ERR(state); + new_global_state = mdp5_get_global_state(s); + if (IS_ERR(new_global_state)) + return PTR_ERR(new_global_state); - /* grab old_state after mdp5_get_state(), since now we hold lock: */ - old_state = &mdp5_kms->state->hwpipe; - new_state = &state->hwpipe; + /* grab old_state after mdp5_get_global_state(), since now we hold lock: */ + old_global_state = mdp5_get_existing_global_state(mdp5_kms); + + old_state = &old_global_state->hwpipe; + new_state = &new_global_state->hwpipe; for (i = 0; i < mdp5_kms->num_hwpipes; i++) { struct mdp5_hw_pipe *cur = mdp5_kms->hwpipes[i]; @@ -107,7 +109,7 @@ int mdp5_pipe_assign(struct drm_atomic_state *s, struct drm_plane *plane, WARN_ON(r_hwpipe); DBG("%s: alloc SMP blocks", (*hwpipe)->name); - ret = mdp5_smp_assign(mdp5_kms->smp, &state->smp, + ret = mdp5_smp_assign(mdp5_kms->smp, &new_global_state->smp, (*hwpipe)->pipe, blkcfg); if (ret) return -ENOMEM; @@ -132,7 +134,7 @@ void mdp5_pipe_release(struct drm_atomic_state *s, struct mdp5_hw_pipe *hwpipe) { struct msm_drm_private *priv = s->dev->dev_private; struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms)); - struct mdp5_state *state = mdp5_get_state(s); + struct mdp5_global_state *state = mdp5_get_global_state(s); struct mdp5_hw_pipe_state *new_state = &state->hwpipe; if (!hwpipe) diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c index a9f31da7d45a..e09bc53a0e65 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c @@ -245,20 +245,6 @@ static const struct drm_plane_funcs mdp5_plane_funcs = { .atomic_print_state = mdp5_plane_atomic_print_state, }; -static int mdp5_plane_prepare_fb(struct drm_plane *plane, - struct drm_plane_state *new_state) -{ - struct mdp5_kms *mdp5_kms = get_kms(plane); - struct msm_kms *kms = &mdp5_kms->base.base; - struct drm_framebuffer *fb = new_state->fb; - - if (!new_state->fb) - return 0; - - DBG("%s: prepare: FB[%u]", plane->name, fb->base.id); - return msm_framebuffer_prepare(fb, kms->aspace); -} - static void mdp5_plane_cleanup_fb(struct drm_plane *plane, struct drm_plane_state *old_state) { @@ -543,7 +529,7 @@ static void mdp5_plane_atomic_async_update(struct drm_plane *plane, } static const struct drm_plane_helper_funcs mdp5_plane_helper_funcs = { - .prepare_fb = mdp5_plane_prepare_fb, + .prepare_fb = msm_atomic_prepare_fb, .cleanup_fb = mdp5_plane_cleanup_fb, .atomic_check = mdp5_plane_atomic_check, .atomic_update = mdp5_plane_atomic_update, diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c index ae4983d9d0a5..96c2b828dba4 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c @@ -340,17 +340,20 @@ void mdp5_smp_dump(struct mdp5_smp *smp, struct drm_printer *p) struct mdp5_kms *mdp5_kms = get_kms(smp); struct mdp5_hw_pipe_state *hwpstate; struct mdp5_smp_state *state; + struct mdp5_global_state *global_state; int total = 0, i, j; drm_printf(p, "name\tinuse\tplane\n"); drm_printf(p, "----\t-----\t-----\n"); if (drm_can_sleep()) - drm_modeset_lock(&mdp5_kms->state_lock, NULL); + drm_modeset_lock(&mdp5_kms->glob_state_lock, NULL); + + global_state = mdp5_get_existing_global_state(mdp5_kms); /* grab these *after* we hold the state_lock */ - hwpstate = &mdp5_kms->state->hwpipe; - state = &mdp5_kms->state->smp; + hwpstate = &global_state->hwpipe; + state = &global_state->smp; for (i = 0; i < mdp5_kms->num_hwpipes; i++) { struct mdp5_hw_pipe *hwpipe = mdp5_kms->hwpipes[i]; @@ -374,7 +377,7 @@ void mdp5_smp_dump(struct mdp5_smp *smp, struct drm_printer *p) bitmap_weight(state->state, smp->blk_cnt)); if (drm_can_sleep()) - drm_modeset_unlock(&mdp5_kms->state_lock); + drm_modeset_unlock(&mdp5_kms->glob_state_lock); } void mdp5_smp_destroy(struct mdp5_smp *smp) @@ -384,7 +387,8 @@ void mdp5_smp_destroy(struct mdp5_smp *smp) struct mdp5_smp *mdp5_smp_init(struct mdp5_kms *mdp5_kms, const struct mdp5_smp_block *cfg) { - struct mdp5_smp_state *state = &mdp5_kms->state->smp; + struct mdp5_smp_state *state; + struct mdp5_global_state *global_state; struct mdp5_smp *smp = NULL; int ret; @@ -398,6 +402,9 @@ struct mdp5_smp *mdp5_smp_init(struct mdp5_kms *mdp5_kms, const struct mdp5_smp_ smp->blk_cnt = cfg->mmb_count; smp->blk_size = cfg->mmb_size; + global_state = mdp5_get_existing_global_state(mdp5_kms); + state = &global_state->smp; + /* statically tied MMBs cannot be re-allocated: */ bitmap_copy(state->state, cfg->reserved_state, smp->blk_cnt); memcpy(smp->reserved, cfg->reserved, sizeof(smp->reserved)); diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 8baba30d6c65..2f1a2780658a 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -1036,7 +1036,6 @@ static int dsi_tx_buf_alloc(struct msm_dsi_host *msm_host, int size) ret = msm_gem_get_iova(msm_host->tx_gem_obj, priv->kms->aspace, &iova); - mutex_unlock(&dev->struct_mutex); if (ret) { pr_err("%s: failed to get iova, %d\n", __func__, ret); return ret; @@ -1067,9 +1066,20 @@ static int dsi_tx_buf_alloc(struct msm_dsi_host *msm_host, int size) static void dsi_tx_buf_free(struct msm_dsi_host *msm_host) { struct drm_device *dev = msm_host->dev; + struct msm_drm_private *priv; + /* + * This is possible if we're tearing down before we've had a chance to + * fully initialize. A very real possibility if our probe is deferred, + * in which case we'll hit msm_dsi_host_destroy() without having run + * through the dsi_tx_buf_alloc(). + */ + if (!dev) + return; + + priv = dev->dev_private; if (msm_host->tx_gem_obj) { - msm_gem_put_iova(msm_host->tx_gem_obj, 0); + msm_gem_put_iova(msm_host->tx_gem_obj, priv->kms->aspace); drm_gem_object_put_unlocked(msm_host->tx_gem_obj); msm_host->tx_gem_obj = NULL; } diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c index e63dc0fb55f8..c79659ca5706 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c @@ -157,8 +157,10 @@ static struct hdmi *msm_hdmi_init(struct platform_device *pdev) hdmi->qfprom_mmio = NULL; } - hdmi->hpd_regs = devm_kzalloc(&pdev->dev, sizeof(hdmi->hpd_regs[0]) * - config->hpd_reg_cnt, GFP_KERNEL); + hdmi->hpd_regs = devm_kcalloc(&pdev->dev, + config->hpd_reg_cnt, + sizeof(hdmi->hpd_regs[0]), + GFP_KERNEL); if (!hdmi->hpd_regs) { ret = -ENOMEM; goto fail; @@ -178,8 +180,10 @@ static struct hdmi *msm_hdmi_init(struct platform_device *pdev) hdmi->hpd_regs[i] = reg; } - hdmi->pwr_regs = devm_kzalloc(&pdev->dev, sizeof(hdmi->pwr_regs[0]) * - config->pwr_reg_cnt, GFP_KERNEL); + hdmi->pwr_regs = devm_kcalloc(&pdev->dev, + config->pwr_reg_cnt, + sizeof(hdmi->pwr_regs[0]), + GFP_KERNEL); if (!hdmi->pwr_regs) { ret = -ENOMEM; goto fail; @@ -199,8 +203,10 @@ static struct hdmi *msm_hdmi_init(struct platform_device *pdev) hdmi->pwr_regs[i] = reg; } - hdmi->hpd_clks = devm_kzalloc(&pdev->dev, sizeof(hdmi->hpd_clks[0]) * - config->hpd_clk_cnt, GFP_KERNEL); + hdmi->hpd_clks = devm_kcalloc(&pdev->dev, + config->hpd_clk_cnt, + sizeof(hdmi->hpd_clks[0]), + GFP_KERNEL); if (!hdmi->hpd_clks) { ret = -ENOMEM; goto fail; @@ -219,8 +225,10 @@ static struct hdmi *msm_hdmi_init(struct platform_device *pdev) hdmi->hpd_clks[i] = clk; } - hdmi->pwr_clks = devm_kzalloc(&pdev->dev, sizeof(hdmi->pwr_clks[0]) * - config->pwr_clk_cnt, GFP_KERNEL); + hdmi->pwr_clks = devm_kcalloc(&pdev->dev, + config->pwr_clk_cnt, + sizeof(hdmi->pwr_clks[0]), + GFP_KERNEL); if (!hdmi->pwr_clks) { ret = -ENOMEM; goto fail; diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c index 5e631392dc85..4157722d6b4d 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c @@ -21,12 +21,12 @@ static int msm_hdmi_phy_resource_init(struct hdmi_phy *phy) struct device *dev = &phy->pdev->dev; int i, ret; - phy->regs = devm_kzalloc(dev, sizeof(phy->regs[0]) * cfg->num_regs, + phy->regs = devm_kcalloc(dev, cfg->num_regs, sizeof(phy->regs[0]), GFP_KERNEL); if (!phy->regs) return -ENOMEM; - phy->clks = devm_kzalloc(dev, sizeof(phy->clks[0]) * cfg->num_clks, + phy->clks = devm_kcalloc(dev, cfg->num_clks, sizeof(phy->clks[0]), GFP_KERNEL); if (!phy->clks) return -ENOMEM; diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index bf5f8c39f34d..f0635c3da7f4 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c @@ -16,69 +16,8 @@ */ #include "msm_drv.h" -#include "msm_kms.h" #include "msm_gem.h" -#include "msm_fence.h" - -struct msm_commit { - struct drm_device *dev; - struct drm_atomic_state *state; - struct work_struct work; - uint32_t crtc_mask; -}; - -static void commit_worker(struct work_struct *work); - -/* block until specified crtcs are no longer pending update, and - * atomically mark them as pending update - */ -static int start_atomic(struct msm_drm_private *priv, uint32_t crtc_mask) -{ - int ret; - - spin_lock(&priv->pending_crtcs_event.lock); - ret = wait_event_interruptible_locked(priv->pending_crtcs_event, - !(priv->pending_crtcs & crtc_mask)); - if (ret == 0) { - DBG("start: %08x", crtc_mask); - priv->pending_crtcs |= crtc_mask; - } - spin_unlock(&priv->pending_crtcs_event.lock); - - return ret; -} - -/* clear specified crtcs (no longer pending update) - */ -static void end_atomic(struct msm_drm_private *priv, uint32_t crtc_mask) -{ - spin_lock(&priv->pending_crtcs_event.lock); - DBG("end: %08x", crtc_mask); - priv->pending_crtcs &= ~crtc_mask; - wake_up_all_locked(&priv->pending_crtcs_event); - spin_unlock(&priv->pending_crtcs_event.lock); -} - -static struct msm_commit *commit_init(struct drm_atomic_state *state) -{ - struct msm_commit *c = kzalloc(sizeof(*c), GFP_KERNEL); - - if (!c) - return NULL; - - c->dev = state->dev; - c->state = state; - - INIT_WORK(&c->work, commit_worker); - - return c; -} - -static void commit_destroy(struct msm_commit *c) -{ - end_atomic(c->dev->dev_private, c->crtc_mask); - kfree(c); -} +#include "msm_kms.h" static void msm_atomic_wait_for_commit_done(struct drm_device *dev, struct drm_atomic_state *old_state) @@ -97,195 +36,48 @@ static void msm_atomic_wait_for_commit_done(struct drm_device *dev, } } -/* The (potentially) asynchronous part of the commit. At this point - * nothing can fail short of armageddon. - */ -static void complete_commit(struct msm_commit *c, bool async) +int msm_atomic_prepare_fb(struct drm_plane *plane, + struct drm_plane_state *new_state) { - struct drm_atomic_state *state = c->state; - struct drm_device *dev = state->dev; - struct msm_drm_private *priv = dev->dev_private; + struct msm_drm_private *priv = plane->dev->dev_private; struct msm_kms *kms = priv->kms; + struct drm_gem_object *obj; + struct msm_gem_object *msm_obj; + struct dma_fence *fence; - drm_atomic_helper_wait_for_fences(dev, state, false); - - kms->funcs->prepare_commit(kms, state); - - drm_atomic_helper_commit_modeset_disables(dev, state); - - drm_atomic_helper_commit_planes(dev, state, 0); - - drm_atomic_helper_commit_modeset_enables(dev, state); - - /* NOTE: _wait_for_vblanks() only waits for vblank on - * enabled CRTCs. So we end up faulting when disabling - * due to (potentially) unref'ing the outgoing fb's - * before the vblank when the disable has latched. - * - * But if it did wait on disabled (or newly disabled) - * CRTCs, that would be racy (ie. we could have missed - * the irq. We need some way to poll for pipe shut - * down. Or just live with occasionally hitting the - * timeout in the CRTC disable path (which really should - * not be critical path) - */ - - msm_atomic_wait_for_commit_done(dev, state); - - drm_atomic_helper_cleanup_planes(dev, state); + if (!new_state->fb) + return 0; - kms->funcs->complete_commit(kms, state); + obj = msm_framebuffer_bo(new_state->fb, 0); + msm_obj = to_msm_bo(obj); + fence = reservation_object_get_excl_rcu(msm_obj->resv); - drm_atomic_state_put(state); + drm_atomic_set_fence_for_plane(new_state, fence); - commit_destroy(c); -} - -static void commit_worker(struct work_struct *work) -{ - complete_commit(container_of(work, struct msm_commit, work), true); + return msm_framebuffer_prepare(new_state->fb, kms->aspace); } -/** - * drm_atomic_helper_commit - commit validated state object - * @dev: DRM device - * @state: the driver state object - * @nonblock: nonblocking commit - * - * This function commits a with drm_atomic_helper_check() pre-validated state - * object. This can still fail when e.g. the framebuffer reservation fails. - * - * RETURNS - * Zero for success or -errno. - */ -int msm_atomic_commit(struct drm_device *dev, - struct drm_atomic_state *state, bool nonblock) +void msm_atomic_commit_tail(struct drm_atomic_state *state) { + struct drm_device *dev = state->dev; struct msm_drm_private *priv = dev->dev_private; - struct msm_commit *c; - struct drm_crtc *crtc; - struct drm_crtc_state *crtc_state; - struct drm_plane *plane; - struct drm_plane_state *old_plane_state, *new_plane_state; - int i, ret; - - ret = drm_atomic_helper_prepare_planes(dev, state); - if (ret) - return ret; - - /* - * Note that plane->atomic_async_check() should fail if we need - * to re-assign hwpipe or anything that touches global atomic - * state, so we'll never go down the async update path in those - * cases. - */ - if (state->async_update) { - drm_atomic_helper_async_commit(dev, state); - drm_atomic_helper_cleanup_planes(dev, state); - return 0; - } - - c = commit_init(state); - if (!c) { - ret = -ENOMEM; - goto error; - } - - /* - * Figure out what crtcs we have: - */ - for_each_new_crtc_in_state(state, crtc, crtc_state, i) - c->crtc_mask |= drm_crtc_mask(crtc); - - /* - * Figure out what fence to wait for: - */ - for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) { - if ((new_plane_state->fb != old_plane_state->fb) && new_plane_state->fb) { - struct drm_gem_object *obj = msm_framebuffer_bo(new_plane_state->fb, 0); - struct msm_gem_object *msm_obj = to_msm_bo(obj); - struct dma_fence *fence = reservation_object_get_excl_rcu(msm_obj->resv); + struct msm_kms *kms = priv->kms; - drm_atomic_set_fence_for_plane(new_plane_state, fence); - } - } + kms->funcs->prepare_commit(kms, state); - /* - * Wait for pending updates on any of the same crtc's and then - * mark our set of crtc's as busy: - */ - ret = start_atomic(dev->dev_private, c->crtc_mask); - if (ret) - goto err_free; + drm_atomic_helper_commit_modeset_disables(dev, state); - BUG_ON(drm_atomic_helper_swap_state(state, false) < 0); + drm_atomic_helper_commit_planes(dev, state, 0); - /* - * This is the point of no return - everything below never fails except - * when the hw goes bonghits. Which means we can commit the new state on - * the software side now. - * - * swap driver private state while still holding state_lock - */ - if (to_kms_state(state)->state) - priv->kms->funcs->swap_state(priv->kms, state); + drm_atomic_helper_commit_modeset_enables(dev, state); - /* - * Everything below can be run asynchronously without the need to grab - * any modeset locks at all under one conditions: It must be guaranteed - * that the asynchronous work has either been cancelled (if the driver - * supports it, which at least requires that the framebuffers get - * cleaned up with drm_atomic_helper_cleanup_planes()) or completed - * before the new state gets committed on the software side with - * drm_atomic_helper_swap_state(). - * - * This scheme allows new atomic state updates to be prepared and - * checked in parallel to the asynchronous completion of the previous - * update. Which is important since compositors need to figure out the - * composition of the next frame right after having submitted the - * current layout. - */ + msm_atomic_wait_for_commit_done(dev, state); - drm_atomic_state_get(state); - if (nonblock) { - queue_work(priv->atomic_wq, &c->work); - return 0; - } + kms->funcs->complete_commit(kms, state); - complete_commit(c, false); + drm_atomic_helper_wait_for_vblanks(dev, state); - return 0; + drm_atomic_helper_commit_hw_done(state); -err_free: - kfree(c); -error: drm_atomic_helper_cleanup_planes(dev, state); - return ret; -} - -struct drm_atomic_state *msm_atomic_state_alloc(struct drm_device *dev) -{ - struct msm_kms_state *state = kzalloc(sizeof(*state), GFP_KERNEL); - - if (!state || drm_atomic_state_init(dev, &state->base) < 0) { - kfree(state); - return NULL; - } - - return &state->base; -} - -void msm_atomic_state_clear(struct drm_atomic_state *s) -{ - struct msm_kms_state *state = to_kms_state(s); - drm_atomic_state_default_clear(&state->base); - kfree(state->state); - state->state = NULL; -} - -void msm_atomic_state_free(struct drm_atomic_state *state) -{ - kfree(to_kms_state(state)->state); - drm_atomic_state_default_release(state); - kfree(state); } diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 30cd514d8f7c..021a0b6f9a59 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -41,10 +41,11 @@ static const struct drm_mode_config_funcs mode_config_funcs = { .fb_create = msm_framebuffer_create, .output_poll_changed = drm_fb_helper_output_poll_changed, .atomic_check = drm_atomic_helper_check, - .atomic_commit = msm_atomic_commit, - .atomic_state_alloc = msm_atomic_state_alloc, - .atomic_state_clear = msm_atomic_state_clear, - .atomic_state_free = msm_atomic_state_free, + .atomic_commit = drm_atomic_helper_commit, +}; + +static const struct drm_mode_config_helper_funcs mode_config_helper_funcs = { + .atomic_commit_tail = msm_atomic_commit_tail, }; #ifdef CONFIG_DRM_MSM_REGISTER_LOGGING @@ -384,7 +385,6 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) priv->wq = alloc_ordered_workqueue("msm", 0); priv->atomic_wq = alloc_ordered_workqueue("msm:atomic", 0); - init_waitqueue_head(&priv->pending_crtcs_event); INIT_LIST_HEAD(&priv->inactive_list); INIT_LIST_HEAD(&priv->vblank_ctrl.event_list); @@ -442,6 +442,7 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) } ddev->mode_config.funcs = &mode_config_funcs; + ddev->mode_config.helper_private = &mode_config_helper_funcs; ret = drm_vblank_init(ddev, priv->num_crtcs); if (ret < 0) { diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 48ed5b9a8580..b2da1fbf81e0 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -117,10 +117,6 @@ struct msm_drm_private { struct workqueue_struct *wq; struct workqueue_struct *atomic_wq; - /* crtcs pending async atomic updates: */ - uint32_t pending_crtcs; - wait_queue_head_t pending_crtcs_event; - unsigned int num_planes; struct drm_plane *planes[16]; @@ -160,8 +156,9 @@ struct msm_format { uint32_t pixel_format; }; -int msm_atomic_commit(struct drm_device *dev, - struct drm_atomic_state *state, bool nonblock); +int msm_atomic_prepare_fb(struct drm_plane *plane, + struct drm_plane_state *new_state); +void msm_atomic_commit_tail(struct drm_atomic_state *state); struct drm_atomic_state *msm_atomic_state_alloc(struct drm_device *dev); void msm_atomic_state_clear(struct drm_atomic_state *state); void msm_atomic_state_free(struct drm_atomic_state *state); diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h index aaa329dc020e..dfd92947de2c 100644 --- a/drivers/gpu/drm/msm/msm_kms.h +++ b/drivers/gpu/drm/msm/msm_kms.h @@ -40,8 +40,6 @@ struct msm_kms_funcs { irqreturn_t (*irq)(struct msm_kms *kms); int (*enable_vblank)(struct msm_kms *kms, struct drm_crtc *crtc); void (*disable_vblank)(struct msm_kms *kms, struct drm_crtc *crtc); - /* swap global atomic state: */ - void (*swap_state)(struct msm_kms *kms, struct drm_atomic_state *state); /* modeset, bracketing atomic_commit(): */ void (*prepare_commit)(struct msm_kms *kms, struct drm_atomic_state *state); void (*complete_commit)(struct msm_kms *kms, struct drm_atomic_state *state); @@ -80,18 +78,6 @@ struct msm_kms { struct msm_gem_address_space *aspace; }; -/** - * Subclass of drm_atomic_state, to allow kms backend to have driver - * private global state. The kms backend can do whatever it wants - * with the ->state ptr. On ->atomic_state_clear() the ->state ptr - * is kfree'd and set back to NULL. - */ -struct msm_kms_state { - struct drm_atomic_state base; - void *state; -}; -#define to_kms_state(x) container_of(x, struct msm_kms_state, base) - static inline void msm_kms_init(struct msm_kms *kms, const struct msm_kms_funcs *funcs) { diff --git a/drivers/gpu/drm/nouveau/nv84_fence.c b/drivers/gpu/drm/nouveau/nv84_fence.c index 090664899247..e721bb2163a0 100644 --- a/drivers/gpu/drm/nouveau/nv84_fence.c +++ b/drivers/gpu/drm/nouveau/nv84_fence.c @@ -141,7 +141,7 @@ nv84_fence_suspend(struct nouveau_drm *drm) struct nv84_fence_priv *priv = drm->fence; int i; - priv->suspend = vmalloc(drm->chan.nr * sizeof(u32)); + priv->suspend = vmalloc(array_size(sizeof(u32), drm->chan.nr)); if (priv->suspend) { for (i = 0; i < drm->chan.nr; i++) priv->suspend[i] = nouveau_bo_rd32(priv->bo, i*4); diff --git a/drivers/gpu/drm/nouveau/nvif/fifo.c b/drivers/gpu/drm/nouveau/nvif/fifo.c index 99d4fd17543c..e84a2e2ff043 100644 --- a/drivers/gpu/drm/nouveau/nvif/fifo.c +++ b/drivers/gpu/drm/nouveau/nvif/fifo.c @@ -50,8 +50,8 @@ nvif_fifo_runlists(struct nvif_device *device) goto done; device->runlists = fls64(a->v.runlists.data); - device->runlist = kzalloc(sizeof(*device->runlist) * - device->runlists, GFP_KERNEL); + device->runlist = kcalloc(device->runlists, sizeof(*device->runlist), + GFP_KERNEL); if (!device->runlist) { ret = -ENOMEM; goto done; diff --git a/drivers/gpu/drm/nouveau/nvif/mmu.c b/drivers/gpu/drm/nouveau/nvif/mmu.c index 358ac4f3cf91..ae08a1ca8044 100644 --- a/drivers/gpu/drm/nouveau/nvif/mmu.c +++ b/drivers/gpu/drm/nouveau/nvif/mmu.c @@ -65,12 +65,15 @@ nvif_mmu_init(struct nvif_object *parent, s32 oclass, struct nvif_mmu *mmu) goto done; mmu->mem = mems[ret].oclass; - mmu->heap = kmalloc(sizeof(*mmu->heap) * mmu->heap_nr, GFP_KERNEL); - mmu->type = kmalloc(sizeof(*mmu->type) * mmu->type_nr, GFP_KERNEL); + mmu->heap = kmalloc_array(mmu->heap_nr, sizeof(*mmu->heap), + GFP_KERNEL); + mmu->type = kmalloc_array(mmu->type_nr, sizeof(*mmu->type), + GFP_KERNEL); if (ret = -ENOMEM, !mmu->heap || !mmu->type) goto done; - mmu->kind = kmalloc(sizeof(*mmu->kind) * mmu->kind_nr, GFP_KERNEL); + mmu->kind = kmalloc_array(mmu->kind_nr, sizeof(*mmu->kind), + GFP_KERNEL); if (!mmu->kind && mmu->kind_nr) goto done; diff --git a/drivers/gpu/drm/nouveau/nvif/object.c b/drivers/gpu/drm/nouveau/nvif/object.c index 40adfe9b334b..ef3f62840e83 100644 --- a/drivers/gpu/drm/nouveau/nvif/object.c +++ b/drivers/gpu/drm/nouveau/nvif/object.c @@ -83,7 +83,7 @@ nvif_object_sclass_get(struct nvif_object *object, struct nvif_sclass **psclass) return ret; } - *psclass = kzalloc(sizeof(**psclass) * args->sclass.count, GFP_KERNEL); + *psclass = kcalloc(args->sclass.count, sizeof(**psclass), GFP_KERNEL); if (*psclass) { for (i = 0; i < args->sclass.count; i++) { (*psclass)[i].oclass = args->sclass.oclass[i].oclass; diff --git a/drivers/gpu/drm/nouveau/nvif/vmm.c b/drivers/gpu/drm/nouveau/nvif/vmm.c index 191832be6c65..6b9c5776547f 100644 --- a/drivers/gpu/drm/nouveau/nvif/vmm.c +++ b/drivers/gpu/drm/nouveau/nvif/vmm.c @@ -138,7 +138,8 @@ nvif_vmm_init(struct nvif_mmu *mmu, s32 oclass, u64 addr, u64 size, vmm->limit = args->size; vmm->page_nr = args->page_nr; - vmm->page = kmalloc(sizeof(*vmm->page) * vmm->page_nr, GFP_KERNEL); + vmm->page = kmalloc_array(vmm->page_nr, sizeof(*vmm->page), + GFP_KERNEL); if (!vmm->page) { ret = -ENOMEM; goto done; diff --git a/drivers/gpu/drm/nouveau/nvkm/core/event.c b/drivers/gpu/drm/nouveau/nvkm/core/event.c index 4e8d3fa042df..006618d77aa4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/event.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/event.c @@ -84,7 +84,8 @@ int nvkm_event_init(const struct nvkm_event_func *func, int types_nr, int index_nr, struct nvkm_event *event) { - event->refs = kzalloc(sizeof(*event->refs) * index_nr * types_nr, + event->refs = kzalloc(array3_size(index_nr, types_nr, + sizeof(*event->refs)), GFP_KERNEL); if (!event->refs) return -ENOMEM; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c index a99046414a18..afccf9721cf0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c @@ -910,7 +910,7 @@ gk104_fifo_oneinit(struct nvkm_fifo *base) nvkm_debug(subdev, "%d PBDMA(s)\n", fifo->pbdma_nr); /* Read PBDMA->runlist(s) mapping from HW. */ - if (!(map = kzalloc(sizeof(*map) * fifo->pbdma_nr, GFP_KERNEL))) + if (!(map = kcalloc(fifo->pbdma_nr, sizeof(*map), GFP_KERNEL))) return -ENOMEM; for (i = 0; i < fifo->pbdma_nr; i++) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/iccsense.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/iccsense.c index 73e463ed55c3..dea444d48f94 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/iccsense.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/iccsense.c @@ -73,7 +73,8 @@ nvbios_iccsense_parse(struct nvkm_bios *bios, struct nvbios_iccsense *iccsense) } iccsense->nr_entry = cnt; - iccsense->rail = kmalloc(sizeof(struct pwr_rail_t) * cnt, GFP_KERNEL); + iccsense->rail = kmalloc_array(cnt, sizeof(struct pwr_rail_t), + GFP_KERNEL); if (!iccsense->rail) return -ENOMEM; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c index 920b3d347803..bbfde1cb3a17 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c @@ -171,7 +171,7 @@ gt215_link_train(struct gt215_ram *ram) return -ENOSYS; /* XXX: Multiple partitions? */ - result = kmalloc(64 * sizeof(u32), GFP_KERNEL); + result = kmalloc_array(64, sizeof(u32), GFP_KERNEL); if (!result) return -ENOMEM; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/mem.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/mem.c index 39808489f21d..92e363dbbc5a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/mem.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/mem.c @@ -191,9 +191,9 @@ nvkm_mem_new_host(struct nvkm_mmu *mmu, int type, u8 page, u64 size, nvkm_memory_ctor(&nvkm_mem_dma, &mem->memory); size = ALIGN(size, PAGE_SIZE) >> PAGE_SHIFT; - if (!(mem->mem = kvmalloc(sizeof(*mem->mem) * size, GFP_KERNEL))) + if (!(mem->mem = kvmalloc_array(size, sizeof(*mem->mem), GFP_KERNEL))) return -ENOMEM; - if (!(mem->dma = kvmalloc(sizeof(*mem->dma) * size, GFP_KERNEL))) + if (!(mem->dma = kvmalloc_array(size, sizeof(*mem->dma), GFP_KERNEL))) return -ENOMEM; if (mmu->dma_bits > 32) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c index 1c12e58f44c2..de269eb482dd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c @@ -59,7 +59,7 @@ nvkm_vmm_pt_new(const struct nvkm_vmm_desc *desc, bool sparse, pgt->sparse = sparse; if (desc->type == PGD) { - pgt->pde = kvzalloc(sizeof(*pgt->pde) * pten, GFP_KERNEL); + pgt->pde = kvcalloc(pten, sizeof(*pgt->pde), GFP_KERNEL); if (!pgt->pde) { kfree(pgt); return NULL; diff --git a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c index 401c02e9e6b2..f92fe205550b 100644 --- a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c +++ b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c @@ -940,8 +940,8 @@ int tiler_map_show(struct seq_file *s, void *arg) h_adj = omap_dmm->container_height / ydiv; w_adj = omap_dmm->container_width / xdiv; - map = kmalloc(h_adj * sizeof(*map), GFP_KERNEL); - global_map = kmalloc((w_adj + 1) * h_adj, GFP_KERNEL); + map = kmalloc_array(h_adj, sizeof(*map), GFP_KERNEL); + global_map = kmalloc_array(w_adj + 1, h_adj, GFP_KERNEL); if (!map || !global_map) goto error; diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c index 0faf042b82e1..17a53d207978 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.c +++ b/drivers/gpu/drm/omapdrm/omap_gem.c @@ -244,7 +244,7 @@ static int omap_gem_attach_pages(struct drm_gem_object *obj) * DSS, GPU, etc. are not cache coherent: */ if (omap_obj->flags & (OMAP_BO_WC|OMAP_BO_UNCACHED)) { - addrs = kmalloc(npages * sizeof(*addrs), GFP_KERNEL); + addrs = kmalloc_array(npages, sizeof(*addrs), GFP_KERNEL); if (!addrs) { ret = -ENOMEM; goto free_pages; @@ -268,7 +268,7 @@ static int omap_gem_attach_pages(struct drm_gem_object *obj) } } } else { - addrs = kzalloc(npages * sizeof(*addrs), GFP_KERNEL); + addrs = kcalloc(npages, sizeof(*addrs), GFP_KERNEL); if (!addrs) { ret = -ENOMEM; goto free_pages; diff --git a/drivers/gpu/drm/qxl/qxl_fb.c b/drivers/gpu/drm/qxl/qxl_fb.c index 9a6752606079..ca465c0d49fa 100644 --- a/drivers/gpu/drm/qxl/qxl_fb.c +++ b/drivers/gpu/drm/qxl/qxl_fb.c @@ -241,7 +241,7 @@ static int qxlfb_create(struct qxl_fbdev *qfbdev, DRM_DEBUG_DRIVER("%dx%d %d\n", mode_cmd.width, mode_cmd.height, mode_cmd.pitches[0]); - shadow = vmalloc(mode_cmd.pitches[0] * mode_cmd.height); + shadow = vmalloc(array_size(mode_cmd.pitches[0], mode_cmd.height)); /* TODO: what's the usual response to memory allocation errors? */ BUG_ON(!shadow); DRM_DEBUG_DRIVER("surface0 at gpu offset %lld, mmap_offset %lld (virt %p, shadow %p)\n", diff --git a/drivers/gpu/drm/qxl/qxl_kms.c b/drivers/gpu/drm/qxl/qxl_kms.c index c5716a0ca3b8..771250aed78d 100644 --- a/drivers/gpu/drm/qxl/qxl_kms.c +++ b/drivers/gpu/drm/qxl/qxl_kms.c @@ -200,8 +200,8 @@ int qxl_device_init(struct qxl_device *qdev, (~(uint64_t)0) >> (qdev->slot_id_bits + qdev->slot_gen_bits); qdev->mem_slots = - kmalloc(qdev->n_mem_slots * sizeof(struct qxl_memslot), - GFP_KERNEL); + kmalloc_array(qdev->n_mem_slots, sizeof(struct qxl_memslot), + GFP_KERNEL); idr_init(&qdev->release_idr); spin_lock_init(&qdev->release_idr_lock); diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c index 6a2e091aa7b6..e55cbeee7a53 100644 --- a/drivers/gpu/drm/radeon/atom.c +++ b/drivers/gpu/drm/radeon/atom.c @@ -1176,7 +1176,7 @@ static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32 ectx.abort = false; ectx.last_jump = 0; if (ws) - ectx.ws = kzalloc(4 * ws, GFP_KERNEL); + ectx.ws = kcalloc(4, ws, GFP_KERNEL); else ectx.ws = NULL; diff --git a/drivers/gpu/drm/radeon/btc_dpm.c b/drivers/gpu/drm/radeon/btc_dpm.c index 95652e643da1..0aef4937c901 100644 --- a/drivers/gpu/drm/radeon/btc_dpm.c +++ b/drivers/gpu/drm/radeon/btc_dpm.c @@ -2581,7 +2581,9 @@ int btc_dpm_init(struct radeon_device *rdev) return ret; rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries = - kzalloc(4 * sizeof(struct radeon_clock_voltage_dependency_entry), GFP_KERNEL); + kcalloc(4, + sizeof(struct radeon_clock_voltage_dependency_entry), + GFP_KERNEL); if (!rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries) { r600_free_extended_power_table(rdev); return -ENOMEM; diff --git a/drivers/gpu/drm/radeon/ci_dpm.c b/drivers/gpu/drm/radeon/ci_dpm.c index 7e1b04dc5593..b9302c918271 100644 --- a/drivers/gpu/drm/radeon/ci_dpm.c +++ b/drivers/gpu/drm/radeon/ci_dpm.c @@ -5568,8 +5568,9 @@ static int ci_parse_power_table(struct radeon_device *rdev) (mode_info->atom_context->bios + data_offset + le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset)); - rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) * - state_array->ucNumEntries, GFP_KERNEL); + rdev->pm.dpm.ps = kcalloc(state_array->ucNumEntries, + sizeof(struct radeon_ps), + GFP_KERNEL); if (!rdev->pm.dpm.ps) return -ENOMEM; power_state_offset = (u8 *)state_array->states; @@ -5770,7 +5771,9 @@ int ci_dpm_init(struct radeon_device *rdev) ci_set_private_data_variables_based_on_pptable(rdev); rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries = - kzalloc(4 * sizeof(struct radeon_clock_voltage_dependency_entry), GFP_KERNEL); + kcalloc(4, + sizeof(struct radeon_clock_voltage_dependency_entry), + GFP_KERNEL); if (!rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries) { ci_dpm_fini(rdev); return -ENOMEM; diff --git a/drivers/gpu/drm/radeon/kv_dpm.c b/drivers/gpu/drm/radeon/kv_dpm.c index ae1529b0ef6f..f055d6ea3522 100644 --- a/drivers/gpu/drm/radeon/kv_dpm.c +++ b/drivers/gpu/drm/radeon/kv_dpm.c @@ -2660,8 +2660,9 @@ static int kv_parse_power_table(struct radeon_device *rdev) (mode_info->atom_context->bios + data_offset + le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset)); - rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) * - state_array->ucNumEntries, GFP_KERNEL); + rdev->pm.dpm.ps = kcalloc(state_array->ucNumEntries, + sizeof(struct radeon_ps), + GFP_KERNEL); if (!rdev->pm.dpm.ps) return -ENOMEM; power_state_offset = (u8 *)state_array->states; diff --git a/drivers/gpu/drm/radeon/ni_dpm.c b/drivers/gpu/drm/radeon/ni_dpm.c index 9416e72f86aa..0fd8d6ba9828 100644 --- a/drivers/gpu/drm/radeon/ni_dpm.c +++ b/drivers/gpu/drm/radeon/ni_dpm.c @@ -3998,8 +3998,9 @@ static int ni_parse_power_table(struct radeon_device *rdev) return -EINVAL; power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); - rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) * - power_info->pplib.ucNumStates, GFP_KERNEL); + rdev->pm.dpm.ps = kcalloc(power_info->pplib.ucNumStates, + sizeof(struct radeon_ps), + GFP_KERNEL); if (!rdev->pm.dpm.ps) return -ENOMEM; @@ -4075,7 +4076,9 @@ int ni_dpm_init(struct radeon_device *rdev) return ret; rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries = - kzalloc(4 * sizeof(struct radeon_clock_voltage_dependency_entry), GFP_KERNEL); + kcalloc(4, + sizeof(struct radeon_clock_voltage_dependency_entry), + GFP_KERNEL); if (!rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries) { r600_free_extended_power_table(rdev); return -ENOMEM; diff --git a/drivers/gpu/drm/radeon/r600_dpm.c b/drivers/gpu/drm/radeon/r600_dpm.c index 31d1b4710844..73d4c5348116 100644 --- a/drivers/gpu/drm/radeon/r600_dpm.c +++ b/drivers/gpu/drm/radeon/r600_dpm.c @@ -991,7 +991,7 @@ int r600_parse_extended_power_table(struct radeon_device *rdev) ATOM_PPLIB_PhaseSheddingLimits_Record *entry; rdev->pm.dpm.dyn_state.phase_shedding_limits_table.entries = - kzalloc(psl->ucNumEntries * + kcalloc(psl->ucNumEntries, sizeof(struct radeon_phase_shedding_limits_entry), GFP_KERNEL); if (!rdev->pm.dpm.dyn_state.phase_shedding_limits_table.entries) { diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 4134759a6823..f422a8d6aec4 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -2126,13 +2126,16 @@ static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev) num_modes = ATOM_MAX_NUMBEROF_POWER_BLOCK; if (num_modes == 0) return state_index; - rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state) * num_modes, GFP_KERNEL); + rdev->pm.power_state = kcalloc(num_modes, + sizeof(struct radeon_power_state), + GFP_KERNEL); if (!rdev->pm.power_state) return state_index; /* last mode is usually default, array is low to high */ for (i = 0; i < num_modes; i++) { rdev->pm.power_state[state_index].clock_info = - kzalloc(sizeof(struct radeon_pm_clock_info) * 1, GFP_KERNEL); + kcalloc(1, sizeof(struct radeon_pm_clock_info), + GFP_KERNEL); if (!rdev->pm.power_state[state_index].clock_info) return state_index; rdev->pm.power_state[state_index].num_clock_modes = 1; @@ -2587,8 +2590,9 @@ static int radeon_atombios_parse_power_table_4_5(struct radeon_device *rdev) radeon_atombios_add_pplib_thermal_controller(rdev, &power_info->pplib.sThermalController); if (power_info->pplib.ucNumStates == 0) return state_index; - rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state) * - power_info->pplib.ucNumStates, GFP_KERNEL); + rdev->pm.power_state = kcalloc(power_info->pplib.ucNumStates, + sizeof(struct radeon_power_state), + GFP_KERNEL); if (!rdev->pm.power_state) return state_index; /* first mode is usually default, followed by low to high */ @@ -2603,10 +2607,11 @@ static int radeon_atombios_parse_power_table_4_5(struct radeon_device *rdev) le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) + (power_state->v1.ucNonClockStateIndex * power_info->pplib.ucNonClockSize)); - rdev->pm.power_state[i].clock_info = kzalloc(sizeof(struct radeon_pm_clock_info) * - ((power_info->pplib.ucStateEntrySize - 1) ? - (power_info->pplib.ucStateEntrySize - 1) : 1), - GFP_KERNEL); + rdev->pm.power_state[i].clock_info = + kcalloc((power_info->pplib.ucStateEntrySize - 1) ? + (power_info->pplib.ucStateEntrySize - 1) : 1, + sizeof(struct radeon_pm_clock_info), + GFP_KERNEL); if (!rdev->pm.power_state[i].clock_info) return state_index; if (power_info->pplib.ucStateEntrySize - 1) { @@ -2688,8 +2693,9 @@ static int radeon_atombios_parse_power_table_6(struct radeon_device *rdev) le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset)); if (state_array->ucNumEntries == 0) return state_index; - rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state) * - state_array->ucNumEntries, GFP_KERNEL); + rdev->pm.power_state = kcalloc(state_array->ucNumEntries, + sizeof(struct radeon_power_state), + GFP_KERNEL); if (!rdev->pm.power_state) return state_index; power_state_offset = (u8 *)state_array->states; @@ -2699,10 +2705,11 @@ static int radeon_atombios_parse_power_table_6(struct radeon_device *rdev) non_clock_array_index = power_state->v2.nonClockInfoIndex; non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) &non_clock_info_array->nonClockInfo[non_clock_array_index]; - rdev->pm.power_state[i].clock_info = kzalloc(sizeof(struct radeon_pm_clock_info) * - (power_state->v2.ucNumDPMLevels ? - power_state->v2.ucNumDPMLevels : 1), - GFP_KERNEL); + rdev->pm.power_state[i].clock_info = + kcalloc(power_state->v2.ucNumDPMLevels ? + power_state->v2.ucNumDPMLevels : 1, + sizeof(struct radeon_pm_clock_info), + GFP_KERNEL); if (!rdev->pm.power_state[i].clock_info) return state_index; if (power_state->v2.ucNumDPMLevels) { @@ -2782,7 +2789,9 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state), GFP_KERNEL); if (rdev->pm.power_state) { rdev->pm.power_state[0].clock_info = - kzalloc(sizeof(struct radeon_pm_clock_info) * 1, GFP_KERNEL); + kcalloc(1, + sizeof(struct radeon_pm_clock_info), + GFP_KERNEL); if (rdev->pm.power_state[0].clock_info) { /* add the default mode */ rdev->pm.power_state[state_index].type = diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 3178ba0c537c..60a61d33f607 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -2642,13 +2642,16 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev) rdev->pm.default_power_state_index = -1; /* allocate 2 power states */ - rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state) * 2, GFP_KERNEL); + rdev->pm.power_state = kcalloc(2, sizeof(struct radeon_power_state), + GFP_KERNEL); if (rdev->pm.power_state) { /* allocate 1 clock mode per state */ rdev->pm.power_state[0].clock_info = - kzalloc(sizeof(struct radeon_pm_clock_info) * 1, GFP_KERNEL); + kcalloc(1, sizeof(struct radeon_pm_clock_info), + GFP_KERNEL); rdev->pm.power_state[1].clock_info = - kzalloc(sizeof(struct radeon_pm_clock_info) * 1, GFP_KERNEL); + kcalloc(1, sizeof(struct radeon_pm_clock_info), + GFP_KERNEL); if (!rdev->pm.power_state[0].clock_info || !rdev->pm.power_state[1].clock_info) goto pm_failed; diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index 0b3ec35515f3..1cef155cc933 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -347,13 +347,14 @@ int radeon_gart_init(struct radeon_device *rdev) DRM_INFO("GART: num cpu pages %u, num gpu pages %u\n", rdev->gart.num_cpu_pages, rdev->gart.num_gpu_pages); /* Allocate pages table */ - rdev->gart.pages = vzalloc(sizeof(void *) * rdev->gart.num_cpu_pages); + rdev->gart.pages = vzalloc(array_size(sizeof(void *), + rdev->gart.num_cpu_pages)); if (rdev->gart.pages == NULL) { radeon_gart_fini(rdev); return -ENOMEM; } - rdev->gart.pages_entry = vmalloc(sizeof(uint64_t) * - rdev->gart.num_gpu_pages); + rdev->gart.pages_entry = vmalloc(array_size(sizeof(uint64_t), + rdev->gart.num_gpu_pages)); if (rdev->gart.pages_entry == NULL) { radeon_gart_fini(rdev); return -ENOMEM; diff --git a/drivers/gpu/drm/radeon/radeon_test.c b/drivers/gpu/drm/radeon/radeon_test.c index f5e9abfadb56..48f4b273e316 100644 --- a/drivers/gpu/drm/radeon/radeon_test.c +++ b/drivers/gpu/drm/radeon/radeon_test.c @@ -59,7 +59,7 @@ static void radeon_do_test_moves(struct radeon_device *rdev, int flag) n = rdev->mc.gtt_size - rdev->gart_pin_size; n /= size; - gtt_obj = kzalloc(n * sizeof(*gtt_obj), GFP_KERNEL); + gtt_obj = kcalloc(n, sizeof(*gtt_obj), GFP_KERNEL); if (!gtt_obj) { DRM_ERROR("Failed to allocate %d pointers\n", n); r = 1; diff --git a/drivers/gpu/drm/radeon/rs780_dpm.c b/drivers/gpu/drm/radeon/rs780_dpm.c index b5e4e09a8996..694b7b3e9799 100644 --- a/drivers/gpu/drm/radeon/rs780_dpm.c +++ b/drivers/gpu/drm/radeon/rs780_dpm.c @@ -804,8 +804,9 @@ static int rs780_parse_power_table(struct radeon_device *rdev) return -EINVAL; power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); - rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) * - power_info->pplib.ucNumStates, GFP_KERNEL); + rdev->pm.dpm.ps = kcalloc(power_info->pplib.ucNumStates, + sizeof(struct radeon_ps), + GFP_KERNEL); if (!rdev->pm.dpm.ps) return -ENOMEM; diff --git a/drivers/gpu/drm/radeon/rv6xx_dpm.c b/drivers/gpu/drm/radeon/rv6xx_dpm.c index d91aa3944593..6986051fbb89 100644 --- a/drivers/gpu/drm/radeon/rv6xx_dpm.c +++ b/drivers/gpu/drm/radeon/rv6xx_dpm.c @@ -1888,8 +1888,9 @@ static int rv6xx_parse_power_table(struct radeon_device *rdev) return -EINVAL; power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); - rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) * - power_info->pplib.ucNumStates, GFP_KERNEL); + rdev->pm.dpm.ps = kcalloc(power_info->pplib.ucNumStates, + sizeof(struct radeon_ps), + GFP_KERNEL); if (!rdev->pm.dpm.ps) return -ENOMEM; diff --git a/drivers/gpu/drm/radeon/rv770_dpm.c b/drivers/gpu/drm/radeon/rv770_dpm.c index cb2a7ec4e217..c765ae7ea806 100644 --- a/drivers/gpu/drm/radeon/rv770_dpm.c +++ b/drivers/gpu/drm/radeon/rv770_dpm.c @@ -2282,8 +2282,9 @@ int rv7xx_parse_power_table(struct radeon_device *rdev) return -EINVAL; power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); - rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) * - power_info->pplib.ucNumStates, GFP_KERNEL); + rdev->pm.dpm.ps = kcalloc(power_info->pplib.ucNumStates, + sizeof(struct radeon_ps), + GFP_KERNEL); if (!rdev->pm.dpm.ps) return -ENOMEM; diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c index 90d5b41007bf..fea88078cf8e 100644 --- a/drivers/gpu/drm/radeon/si_dpm.c +++ b/drivers/gpu/drm/radeon/si_dpm.c @@ -6832,8 +6832,9 @@ static int si_parse_power_table(struct radeon_device *rdev) (mode_info->atom_context->bios + data_offset + le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset)); - rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) * - state_array->ucNumEntries, GFP_KERNEL); + rdev->pm.dpm.ps = kcalloc(state_array->ucNumEntries, + sizeof(struct radeon_ps), + GFP_KERNEL); if (!rdev->pm.dpm.ps) return -ENOMEM; power_state_offset = (u8 *)state_array->states; @@ -6941,7 +6942,9 @@ int si_dpm_init(struct radeon_device *rdev) return ret; rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries = - kzalloc(4 * sizeof(struct radeon_clock_voltage_dependency_entry), GFP_KERNEL); + kcalloc(4, + sizeof(struct radeon_clock_voltage_dependency_entry), + GFP_KERNEL); if (!rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries) { r600_free_extended_power_table(rdev); return -ENOMEM; diff --git a/drivers/gpu/drm/radeon/sumo_dpm.c b/drivers/gpu/drm/radeon/sumo_dpm.c index fd4804829e46..1e4975f3374c 100644 --- a/drivers/gpu/drm/radeon/sumo_dpm.c +++ b/drivers/gpu/drm/radeon/sumo_dpm.c @@ -1482,8 +1482,9 @@ static int sumo_parse_power_table(struct radeon_device *rdev) (mode_info->atom_context->bios + data_offset + le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset)); - rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) * - state_array->ucNumEntries, GFP_KERNEL); + rdev->pm.dpm.ps = kcalloc(state_array->ucNumEntries, + sizeof(struct radeon_ps), + GFP_KERNEL); if (!rdev->pm.dpm.ps) return -ENOMEM; power_state_offset = (u8 *)state_array->states; diff --git a/drivers/gpu/drm/radeon/trinity_dpm.c b/drivers/gpu/drm/radeon/trinity_dpm.c index 2ef7c4e5e495..5d317f763eea 100644 --- a/drivers/gpu/drm/radeon/trinity_dpm.c +++ b/drivers/gpu/drm/radeon/trinity_dpm.c @@ -1757,8 +1757,9 @@ static int trinity_parse_power_table(struct radeon_device *rdev) (mode_info->atom_context->bios + data_offset + le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset)); - rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) * - state_array->ucNumEntries, GFP_KERNEL); + rdev->pm.dpm.ps = kcalloc(state_array->ucNumEntries, + sizeof(struct radeon_ps), + GFP_KERNEL); if (!rdev->pm.dpm.ps) return -ENOMEM; power_state_offset = (u8 *)state_array->states; diff --git a/drivers/gpu/drm/savage/savage_bci.c b/drivers/gpu/drm/savage/savage_bci.c index 2a5b8466d806..35dc74883f83 100644 --- a/drivers/gpu/drm/savage/savage_bci.c +++ b/drivers/gpu/drm/savage/savage_bci.c @@ -298,8 +298,9 @@ static int savage_dma_init(drm_savage_private_t * dev_priv) dev_priv->nr_dma_pages = dev_priv->cmd_dma->size / (SAVAGE_DMA_PAGE_SIZE * 4); - dev_priv->dma_pages = kmalloc(sizeof(drm_savage_dma_page_t) * - dev_priv->nr_dma_pages, GFP_KERNEL); + dev_priv->dma_pages = kmalloc_array(dev_priv->nr_dma_pages, + sizeof(drm_savage_dma_page_t), + GFP_KERNEL); if (dev_priv->dma_pages == NULL) return -ENOMEM; diff --git a/drivers/gpu/drm/scheduler/gpu_scheduler.c b/drivers/gpu/drm/scheduler/gpu_scheduler.c index df1578d6f42e..44d480768dfe 100644 --- a/drivers/gpu/drm/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/scheduler/gpu_scheduler.c @@ -349,8 +349,13 @@ static bool drm_sched_entity_add_dependency_cb(struct drm_sched_entity *entity) struct dma_fence * fence = entity->dependency; struct drm_sched_fence *s_fence; - if (fence->context == entity->fence_context) { - /* We can ignore fences from ourself */ + if (fence->context == entity->fence_context || + fence->context == entity->fence_context + 1) { + /* + * Fence is a scheduled/finished fence from a job + * which belongs to the same entity, we can ignore + * fences from ourself + */ dma_fence_put(entity->dependency); return false; } diff --git a/drivers/gpu/drm/selftests/test-drm_mm.c b/drivers/gpu/drm/selftests/test-drm_mm.c index 7cc935d7b7aa..933af1c25387 100644 --- a/drivers/gpu/drm/selftests/test-drm_mm.c +++ b/drivers/gpu/drm/selftests/test-drm_mm.c @@ -389,7 +389,7 @@ static int __igt_reserve(unsigned int count, u64 size) if (!order) goto err; - nodes = vzalloc(sizeof(*nodes) * count); + nodes = vzalloc(array_size(count, sizeof(*nodes))); if (!nodes) goto err_order; @@ -579,7 +579,7 @@ static int __igt_insert(unsigned int count, u64 size, bool replace) DRM_MM_BUG_ON(!size); ret = -ENOMEM; - nodes = vmalloc(count * sizeof(*nodes)); + nodes = vmalloc(array_size(count, sizeof(*nodes))); if (!nodes) goto err; @@ -889,7 +889,7 @@ static int __igt_insert_range(unsigned int count, u64 size, u64 start, u64 end) */ ret = -ENOMEM; - nodes = vzalloc(count * sizeof(*nodes)); + nodes = vzalloc(array_size(count, sizeof(*nodes))); if (!nodes) goto err; @@ -1046,7 +1046,7 @@ static int igt_align(void *ignored) * meets our requirements. */ - nodes = vzalloc(max_count * sizeof(*nodes)); + nodes = vzalloc(array_size(max_count, sizeof(*nodes))); if (!nodes) goto err; @@ -1416,7 +1416,7 @@ static int igt_evict(void *ignored) */ ret = -ENOMEM; - nodes = vzalloc(size * sizeof(*nodes)); + nodes = vzalloc(array_size(size, sizeof(*nodes))); if (!nodes) goto err; @@ -1526,7 +1526,7 @@ static int igt_evict_range(void *ignored) */ ret = -ENOMEM; - nodes = vzalloc(size * sizeof(*nodes)); + nodes = vzalloc(array_size(size, sizeof(*nodes))); if (!nodes) goto err; @@ -1627,11 +1627,11 @@ static int igt_topdown(void *ignored) */ ret = -ENOMEM; - nodes = vzalloc(count * sizeof(*nodes)); + nodes = vzalloc(array_size(count, sizeof(*nodes))); if (!nodes) goto err; - bitmap = kzalloc(count / BITS_PER_LONG * sizeof(unsigned long), + bitmap = kcalloc(count / BITS_PER_LONG, sizeof(unsigned long), GFP_KERNEL); if (!bitmap) goto err_nodes; @@ -1741,11 +1741,11 @@ static int igt_bottomup(void *ignored) */ ret = -ENOMEM; - nodes = vzalloc(count * sizeof(*nodes)); + nodes = vzalloc(array_size(count, sizeof(*nodes))); if (!nodes) goto err; - bitmap = kzalloc(count / BITS_PER_LONG * sizeof(unsigned long), + bitmap = kcalloc(count / BITS_PER_LONG, sizeof(unsigned long), GFP_KERNEL); if (!bitmap) goto err_nodes; @@ -2098,7 +2098,7 @@ static int igt_color_evict(void *ignored) */ ret = -ENOMEM; - nodes = vzalloc(total_size * sizeof(*nodes)); + nodes = vzalloc(array_size(total_size, sizeof(*nodes))); if (!nodes) goto err; @@ -2199,7 +2199,7 @@ static int igt_color_evict_range(void *ignored) */ ret = -ENOMEM; - nodes = vzalloc(total_size * sizeof(*nodes)); + nodes = vzalloc(array_size(total_size, sizeof(*nodes))); if (!nodes) goto err; diff --git a/drivers/gpu/drm/tinydrm/repaper.c b/drivers/gpu/drm/tinydrm/repaper.c index 1ee6855212a0..50a1d4216ce7 100644 --- a/drivers/gpu/drm/tinydrm/repaper.c +++ b/drivers/gpu/drm/tinydrm/repaper.c @@ -548,7 +548,7 @@ static int repaper_fb_dirty(struct drm_framebuffer *fb, DRM_DEBUG("Flushing [FB:%d] st=%ums\n", fb->base.id, epd->factored_stage_time); - buf = kmalloc(fb->width * fb->height, GFP_KERNEL); + buf = kmalloc_array(fb->width, fb->height, GFP_KERNEL); if (!buf) return -ENOMEM; diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc.c b/drivers/gpu/drm/ttm/ttm_page_alloc.c index 06c94e3a5f15..6e2d1300b457 100644 --- a/drivers/gpu/drm/ttm/ttm_page_alloc.c +++ b/drivers/gpu/drm/ttm/ttm_page_alloc.c @@ -348,8 +348,9 @@ static int ttm_page_pool_free(struct ttm_page_pool *pool, unsigned nr_free, if (use_static) pages_to_free = static_buf; else - pages_to_free = kmalloc(npages_to_free * sizeof(struct page *), - GFP_KERNEL); + pages_to_free = kmalloc_array(npages_to_free, + sizeof(struct page *), + GFP_KERNEL); if (!pages_to_free) { pr_debug("Failed to allocate memory for pool free operation\n"); return 0; @@ -547,7 +548,8 @@ static int ttm_alloc_new_pages(struct list_head *pages, gfp_t gfp_flags, unsigned max_cpages = min(count << order, (unsigned)NUM_PAGES_TO_ALLOC); /* allocate array for page caching change */ - caching_array = kmalloc(max_cpages*sizeof(struct page *), GFP_KERNEL); + caching_array = kmalloc_array(max_cpages, sizeof(struct page *), + GFP_KERNEL); if (!caching_array) { pr_debug("Unable to allocate table for new pages\n"); diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c b/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c index f63d99c302e4..3f14c1cc0789 100644 --- a/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c +++ b/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c @@ -463,8 +463,9 @@ static unsigned ttm_dma_page_pool_free(struct dma_pool *pool, unsigned nr_free, if (use_static) pages_to_free = static_buf; else - pages_to_free = kmalloc(npages_to_free * sizeof(struct page *), - GFP_KERNEL); + pages_to_free = kmalloc_array(npages_to_free, + sizeof(struct page *), + GFP_KERNEL); if (!pages_to_free) { pr_debug("%s: Failed to allocate memory for pool free operation\n", @@ -753,7 +754,8 @@ static int ttm_dma_pool_alloc_new_pages(struct dma_pool *pool, (unsigned)(PAGE_SIZE/sizeof(struct page *))); /* allocate array for page caching change */ - caching_array = kmalloc(max_cpages*sizeof(struct page *), GFP_KERNEL); + caching_array = kmalloc_array(max_cpages, sizeof(struct page *), + GFP_KERNEL); if (!caching_array) { pr_debug("%s: Unable to allocate table for new pages\n", diff --git a/drivers/gpu/drm/v3d/Kconfig b/drivers/gpu/drm/v3d/Kconfig index a0c0259355bd..1552bf552c94 100644 --- a/drivers/gpu/drm/v3d/Kconfig +++ b/drivers/gpu/drm/v3d/Kconfig @@ -3,6 +3,7 @@ config DRM_V3D depends on ARCH_BCM || ARCH_BCMSTB || COMPILE_TEST depends on DRM depends on COMMON_CLK + depends on MMU select DRM_SCHED help Choose this option if you have a system that has a Broadcom diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 71d44c357d35..1d34619eb3fe 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -209,7 +209,7 @@ static void vc4_dlist_write(struct vc4_plane_state *vc4_state, u32 val) { if (vc4_state->dlist_count == vc4_state->dlist_size) { u32 new_size = max(4u, vc4_state->dlist_count * 2); - u32 *new_dlist = kmalloc(new_size * 4, GFP_KERNEL); + u32 *new_dlist = kmalloc_array(new_size, 4, GFP_KERNEL); if (!new_dlist) return; diff --git a/drivers/gpu/drm/via/via_dmablit.c b/drivers/gpu/drm/via/via_dmablit.c index d6e84a589ef1..345bda4494e1 100644 --- a/drivers/gpu/drm/via/via_dmablit.c +++ b/drivers/gpu/drm/via/via_dmablit.c @@ -235,7 +235,7 @@ via_lock_all_dma_pages(drm_via_sg_info_t *vsg, drm_via_dmablit_t *xfer) vsg->num_pages = VIA_PFN(xfer->mem_addr + (xfer->num_lines * xfer->mem_stride - 1)) - first_pfn + 1; - vsg->pages = vzalloc(sizeof(struct page *) * vsg->num_pages); + vsg->pages = vzalloc(array_size(sizeof(struct page *), vsg->num_pages)); if (NULL == vsg->pages) return -ENOMEM; ret = get_user_pages_fast((unsigned long)xfer->mem_addr, diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 355dc7e49562..f858cc72011d 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -134,8 +134,11 @@ static int open_collection(struct hid_parser *parser, unsigned type) } if (parser->device->maxcollection == parser->device->collection_size) { - collection = kmalloc(sizeof(struct hid_collection) * - parser->device->collection_size * 2, GFP_KERNEL); + collection = kmalloc( + array3_size(sizeof(struct hid_collection), + parser->device->collection_size, + 2), + GFP_KERNEL); if (collection == NULL) { hid_err(parser->device, "failed to reallocate collection array\n"); return -ENOMEM; @@ -1278,7 +1281,7 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field, __s32 max = field->logical_maximum; __s32 *value; - value = kmalloc(sizeof(__s32) * count, GFP_ATOMIC); + value = kmalloc_array(count, sizeof(__s32), GFP_ATOMIC); if (!value) return; diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index 4f4e7a08a07b..8469b6964ff6 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c @@ -457,7 +457,7 @@ static char *resolv_usage_page(unsigned page, struct seq_file *f) { char *buf = NULL; if (!f) { - buf = kzalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_ATOMIC); + buf = kzalloc(HID_DEBUG_BUFSIZE, GFP_ATOMIC); if (!buf) return ERR_PTR(-ENOMEM); } @@ -685,7 +685,7 @@ void hid_dump_report(struct hid_device *hid, int type, u8 *data, char *buf; unsigned int i; - buf = kmalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_ATOMIC); + buf = kmalloc(HID_DEBUG_BUFSIZE, GFP_ATOMIC); if (!buf) return; @@ -1088,7 +1088,7 @@ static int hid_debug_events_open(struct inode *inode, struct file *file) goto out; } - if (!(list->hid_debug_buf = kzalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_KERNEL))) { + if (!(list->hid_debug_buf = kzalloc(HID_DEBUG_BUFSIZE, GFP_KERNEL))) { err = -ENOMEM; kfree(list); goto out; diff --git a/drivers/hid/hid-picolcd_fb.c b/drivers/hid/hid-picolcd_fb.c index 7f965e231433..864a084b6cba 100644 --- a/drivers/hid/hid-picolcd_fb.c +++ b/drivers/hid/hid-picolcd_fb.c @@ -394,7 +394,8 @@ static int picolcd_set_par(struct fb_info *info) return -EINVAL; o_fb = fbdata->bitmap; - tmp_fb = kmalloc(PICOLCDFB_SIZE*info->var.bits_per_pixel, GFP_KERNEL); + tmp_fb = kmalloc_array(PICOLCDFB_SIZE, info->var.bits_per_pixel, + GFP_KERNEL); if (!tmp_fb) return -ENOMEM; diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c index 25363fc571bc..50af72baa5ca 100644 --- a/drivers/hid/hid-sensor-hub.c +++ b/drivers/hid/hid-sensor-hub.c @@ -624,7 +624,8 @@ static int sensor_hub_probe(struct hid_device *hdev, ret = -EINVAL; goto err_stop_hw; } - sd->hid_sensor_hub_client_devs = devm_kzalloc(&hdev->dev, dev_cnt * + sd->hid_sensor_hub_client_devs = devm_kcalloc(&hdev->dev, + dev_cnt, sizeof(struct mfd_cell), GFP_KERNEL); if (sd->hid_sensor_hub_client_devs == NULL) { diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index b39844adea47..4a44e48e08b2 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -218,7 +218,7 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t goto out; } - buf = kmalloc(count * sizeof(__u8), GFP_KERNEL); + buf = kmalloc(count, GFP_KERNEL); if (!buf) { ret = -ENOMEM; goto out; diff --git a/drivers/hid/intel-ish-hid/ishtp-hid-client.c b/drivers/hid/intel-ish-hid/ishtp-hid-client.c index acc2536c8094..2d28cffc1404 100644 --- a/drivers/hid/intel-ish-hid/ishtp-hid-client.c +++ b/drivers/hid/intel-ish-hid/ishtp-hid-client.c @@ -121,9 +121,9 @@ static void process_recv(struct ishtp_cl *hid_ishtp_cl, void *recv_buf, } client_data->hid_dev_count = (unsigned int)*payload; if (!client_data->hid_devices) - client_data->hid_devices = devm_kzalloc( + client_data->hid_devices = devm_kcalloc( &client_data->cl_device->dev, - client_data->hid_dev_count * + client_data->hid_dev_count, sizeof(struct device_info), GFP_KERNEL); if (!client_data->hid_devices) { diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index ee7a37eb159a..c101369b51de 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -1363,7 +1363,7 @@ static int wacom_led_groups_alloc_and_register_one(struct device *dev, if (!devres_open_group(dev, &wacom->led.groups[group_id], GFP_KERNEL)) return -ENOMEM; - leds = devm_kzalloc(dev, sizeof(struct wacom_led) * count, GFP_KERNEL); + leds = devm_kcalloc(dev, count, sizeof(struct wacom_led), GFP_KERNEL); if (!leds) { error = -ENOMEM; goto err; @@ -1463,7 +1463,7 @@ static int wacom_led_groups_allocate(struct wacom *wacom, int count) struct wacom_group_leds *groups; int error; - groups = devm_kzalloc(dev, sizeof(struct wacom_group_leds) * count, + groups = devm_kcalloc(dev, count, sizeof(struct wacom_group_leds), GFP_KERNEL); if (!groups) return -ENOMEM; diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c index 9b82549cbbc8..658dc765753b 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c @@ -190,7 +190,7 @@ int hv_synic_alloc(void) { int cpu; - hv_context.hv_numa_map = kzalloc(sizeof(struct cpumask) * nr_node_ids, + hv_context.hv_numa_map = kcalloc(nr_node_ids, sizeof(struct cpumask), GFP_KERNEL); if (hv_context.hv_numa_map == NULL) { pr_err("Unable to allocate NUMA map\n"); diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c index 3c836c099a8f..be3c8b10b84a 100644 --- a/drivers/hv/ring_buffer.c +++ b/drivers/hv/ring_buffer.c @@ -202,7 +202,7 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, * First page holds struct hv_ring_buffer, do wraparound mapping for * the rest. */ - pages_wraparound = kzalloc(sizeof(struct page *) * (page_cnt * 2 - 1), + pages_wraparound = kcalloc(page_cnt * 2 - 1, sizeof(struct page *), GFP_KERNEL); if (!pages_wraparound) return -ENOMEM; diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c index 14a94d90c028..34e45b97629e 100644 --- a/drivers/hwmon/acpi_power_meter.c +++ b/drivers/hwmon/acpi_power_meter.c @@ -575,8 +575,9 @@ static int read_domain_devices(struct acpi_power_meter_resource *resource) if (!pss->package.count) goto end; - resource->domain_devices = kzalloc(sizeof(struct acpi_device *) * - pss->package.count, GFP_KERNEL); + resource->domain_devices = kcalloc(pss->package.count, + sizeof(struct acpi_device *), + GFP_KERNEL); if (!resource->domain_devices) { res = -ENOMEM; goto end; @@ -796,7 +797,7 @@ static int read_capabilities(struct acpi_power_meter_resource *resource) goto error; } - *str = kzalloc(sizeof(u8) * (element->string.length + 1), + *str = kcalloc(element->string.length + 1, sizeof(u8), GFP_KERNEL); if (!*str) { res = -ENOMEM; diff --git a/drivers/hwmon/aspeed-pwm-tacho.c b/drivers/hwmon/aspeed-pwm-tacho.c index 693a3d53cab5..5e449eac788a 100644 --- a/drivers/hwmon/aspeed-pwm-tacho.c +++ b/drivers/hwmon/aspeed-pwm-tacho.c @@ -894,7 +894,7 @@ static int aspeed_create_fan(struct device *dev, count = of_property_count_u8_elems(child, "aspeed,fan-tach-ch"); if (count < 1) return -EINVAL; - fan_tach_ch = devm_kzalloc(dev, sizeof(*fan_tach_ch) * count, + fan_tach_ch = devm_kcalloc(dev, count, sizeof(*fan_tach_ch), GFP_KERNEL); if (!fan_tach_ch) return -ENOMEM; diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 72c338eb5fae..10645c9bb7be 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -742,7 +742,7 @@ static int __init coretemp_init(void) return -ENODEV; max_packages = topology_max_packages(); - pkg_devices = kzalloc(max_packages * sizeof(struct platform_device *), + pkg_devices = kcalloc(max_packages, sizeof(struct platform_device *), GFP_KERNEL); if (!pkg_devices) return -ENOMEM; diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c index 5c9a52599cf6..a3974cddef07 100644 --- a/drivers/hwmon/gpio-fan.c +++ b/drivers/hwmon/gpio-fan.c @@ -441,8 +441,8 @@ static int gpio_fan_get_of_data(struct gpio_fan_data *fan_data) dev_err(dev, "DT properties empty / missing"); return -ENODEV; } - gpios = devm_kzalloc(dev, - fan_data->num_gpios * sizeof(struct gpio_desc *), + gpios = devm_kcalloc(dev, + fan_data->num_gpios, sizeof(struct gpio_desc *), GFP_KERNEL); if (!gpios) return -ENOMEM; @@ -471,8 +471,8 @@ static int gpio_fan_get_of_data(struct gpio_fan_data *fan_data) * Speed map is in the form <RPM ctrl_val RPM ctrl_val ...> * this needs splitting into pairs to create gpio_fan_speed structs */ - speed = devm_kzalloc(dev, - fan_data->num_speed * sizeof(struct gpio_fan_speed), + speed = devm_kcalloc(dev, + fan_data->num_speed, sizeof(struct gpio_fan_speed), GFP_KERNEL); if (!speed) return -ENOMEM; diff --git a/drivers/hwmon/i5k_amb.c b/drivers/hwmon/i5k_amb.c index 9397d2f0e79a..a4edc43dd060 100644 --- a/drivers/hwmon/i5k_amb.c +++ b/drivers/hwmon/i5k_amb.c @@ -274,8 +274,9 @@ static int i5k_amb_hwmon_init(struct platform_device *pdev) num_ambs += hweight16(data->amb_present[i] & 0x7fff); /* Set up sysfs stuff */ - data->attrs = kzalloc(sizeof(*data->attrs) * num_ambs * KNOBS_PER_AMB, - GFP_KERNEL); + data->attrs = kzalloc(array3_size(num_ambs, KNOBS_PER_AMB, + sizeof(*data->attrs)), + GFP_KERNEL); if (!data->attrs) return -ENOMEM; data->num_attrs = 0; diff --git a/drivers/hwmon/ibmpex.c b/drivers/hwmon/ibmpex.c index 21b9c72f16bd..ab72cabf5a95 100644 --- a/drivers/hwmon/ibmpex.c +++ b/drivers/hwmon/ibmpex.c @@ -387,7 +387,7 @@ static int ibmpex_find_sensors(struct ibmpex_bmc_data *data) return -ENOENT; data->num_sensors = err; - data->sensors = kzalloc(data->num_sensors * sizeof(*data->sensors), + data->sensors = kcalloc(data->num_sensors, sizeof(*data->sensors), GFP_KERNEL); if (!data->sensors) return -ENOMEM; diff --git a/drivers/hwmon/ibmpowernv.c b/drivers/hwmon/ibmpowernv.c index 0298745d46e4..f829dadfd5a0 100644 --- a/drivers/hwmon/ibmpowernv.c +++ b/drivers/hwmon/ibmpowernv.c @@ -326,9 +326,9 @@ static int populate_attr_groups(struct platform_device *pdev) of_node_put(opal); for (type = 0; type < MAX_SENSOR_TYPE; type++) { - sensor_groups[type].group.attrs = devm_kzalloc(&pdev->dev, - sizeof(struct attribute *) * - (sensor_groups[type].attr_count + 1), + sensor_groups[type].group.attrs = devm_kcalloc(&pdev->dev, + sensor_groups[type].attr_count + 1, + sizeof(struct attribute *), GFP_KERNEL); if (!sensor_groups[type].group.attrs) return -ENOMEM; @@ -409,7 +409,8 @@ static int create_device_attrs(struct platform_device *pdev) int err = 0; opal = of_find_node_by_path("/ibm,opal/sensors"); - sdata = devm_kzalloc(&pdev->dev, pdata->sensors_count * sizeof(*sdata), + sdata = devm_kcalloc(&pdev->dev, + pdata->sensors_count, sizeof(*sdata), GFP_KERNEL); if (!sdata) { err = -ENOMEM; diff --git a/drivers/hwmon/iio_hwmon.c b/drivers/hwmon/iio_hwmon.c index 5e5b32a1ec4b..69031a0f7ed2 100644 --- a/drivers/hwmon/iio_hwmon.c +++ b/drivers/hwmon/iio_hwmon.c @@ -92,8 +92,8 @@ static int iio_hwmon_probe(struct platform_device *pdev) while (st->channels[st->num_channels].indio_dev) st->num_channels++; - st->attrs = devm_kzalloc(dev, - sizeof(*st->attrs) * (st->num_channels + 1), + st->attrs = devm_kcalloc(dev, + st->num_channels + 1, sizeof(*st->attrs), GFP_KERNEL); if (st->attrs == NULL) { ret = -ENOMEM; diff --git a/drivers/hwmon/nct6683.c b/drivers/hwmon/nct6683.c index b0bc77bf2cd9..a753464a1a33 100644 --- a/drivers/hwmon/nct6683.c +++ b/drivers/hwmon/nct6683.c @@ -426,12 +426,12 @@ nct6683_create_attr_group(struct device *dev, if (group == NULL) return ERR_PTR(-ENOMEM); - attrs = devm_kzalloc(dev, sizeof(*attrs) * (repeat * count + 1), + attrs = devm_kcalloc(dev, repeat * count + 1, sizeof(*attrs), GFP_KERNEL); if (attrs == NULL) return ERR_PTR(-ENOMEM); - su = devm_kzalloc(dev, sizeof(*su) * repeat * count, + su = devm_kzalloc(dev, array3_size(repeat, count, sizeof(*su)), GFP_KERNEL); if (su == NULL) return ERR_PTR(-ENOMEM); diff --git a/drivers/hwmon/nct6775.c b/drivers/hwmon/nct6775.c index aebce560bfaf..155d4d1d1585 100644 --- a/drivers/hwmon/nct6775.c +++ b/drivers/hwmon/nct6775.c @@ -1190,12 +1190,12 @@ nct6775_create_attr_group(struct device *dev, if (group == NULL) return ERR_PTR(-ENOMEM); - attrs = devm_kzalloc(dev, sizeof(*attrs) * (repeat * count + 1), + attrs = devm_kcalloc(dev, repeat * count + 1, sizeof(*attrs), GFP_KERNEL); if (attrs == NULL) return ERR_PTR(-ENOMEM); - su = devm_kzalloc(dev, sizeof(*su) * repeat * count, + su = devm_kzalloc(dev, array3_size(repeat, count, sizeof(*su)), GFP_KERNEL); if (su == NULL) return ERR_PTR(-ENOMEM); diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index f7c47d7994e7..82c3754e21e3 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -2176,8 +2176,8 @@ static int pmbus_init_debugfs(struct i2c_client *client, } /* Allocate the max possible entries we need. */ - entries = devm_kzalloc(data->dev, - sizeof(*entries) * (data->info->pages * 10), + entries = devm_kcalloc(data->dev, + data->info->pages * 10, sizeof(*entries), GFP_KERNEL); if (!entries) return -ENOMEM; diff --git a/drivers/hwmon/pmbus/ucd9000.c b/drivers/hwmon/pmbus/ucd9000.c index 70cecb06f93c..ae93885fccd8 100644 --- a/drivers/hwmon/pmbus/ucd9000.c +++ b/drivers/hwmon/pmbus/ucd9000.c @@ -454,8 +454,8 @@ static int ucd9000_init_debugfs(struct i2c_client *client, */ if (mid->driver_data == ucd9090 || mid->driver_data == ucd90160 || mid->driver_data == ucd90910) { - entries = devm_kzalloc(&client->dev, - sizeof(*entries) * UCD9000_GPI_COUNT, + entries = devm_kcalloc(&client->dev, + UCD9000_GPI_COUNT, sizeof(*entries), GFP_KERNEL); if (!entries) return -ENOMEM; diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c index 70cc0d134f3c..7838af58f92d 100644 --- a/drivers/hwmon/pwm-fan.c +++ b/drivers/hwmon/pwm-fan.c @@ -180,7 +180,7 @@ static int pwm_fan_of_get_cooling_data(struct device *dev, } num = ret; - ctx->pwm_fan_cooling_levels = devm_kzalloc(dev, num * sizeof(u32), + ctx->pwm_fan_cooling_levels = devm_kcalloc(dev, num, sizeof(u32), GFP_KERNEL); if (!ctx->pwm_fan_cooling_levels) return -ENOMEM; diff --git a/drivers/hwspinlock/Kconfig b/drivers/hwspinlock/Kconfig index f0f467983960..e895d29500ee 100644 --- a/drivers/hwspinlock/Kconfig +++ b/drivers/hwspinlock/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # Generic HWSPINLOCK framework # diff --git a/drivers/hwspinlock/hwspinlock_core.c b/drivers/hwspinlock/hwspinlock_core.c index 4074441444fe..d16e6a3d38e8 100644 --- a/drivers/hwspinlock/hwspinlock_core.c +++ b/drivers/hwspinlock/hwspinlock_core.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Hardware spinlock framework * * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com * * Contact: Ohad Ben-Cohen <ohad@wizery.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * - * 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. */ #define pr_fmt(fmt) "%s: " fmt, __func__ @@ -71,10 +63,16 @@ static DEFINE_MUTEX(hwspinlock_tree_lock); * This function attempts to lock an hwspinlock, and will immediately * fail if the hwspinlock is already taken. * - * Upon a successful return from this function, preemption (and possibly - * interrupts) is disabled, so the caller must not sleep, and is advised to - * release the hwspinlock as soon as possible. This is required in order to - * minimize remote cores polling on the hardware interconnect. + * Caution: If the mode is HWLOCK_RAW, that means user must protect the routine + * of getting hardware lock with mutex or spinlock. Since in some scenarios, + * user need some time-consuming or sleepable operations under the hardware + * lock, they need one sleepable lock (like mutex) to protect the operations. + * + * If the mode is not HWLOCK_RAW, upon a successful return from this function, + * preemption (and possibly interrupts) is disabled, so the caller must not + * sleep, and is advised to release the hwspinlock as soon as possible. This is + * required in order to minimize remote cores polling on the hardware + * interconnect. * * The user decides whether local interrupts are disabled or not, and if yes, * whether he wants their previous state to be saved. It is up to the user @@ -106,12 +104,20 @@ int __hwspin_trylock(struct hwspinlock *hwlock, int mode, unsigned long *flags) * problems with hwspinlock usage (e.g. scheduler checks like * 'scheduling while atomic' etc.) */ - if (mode == HWLOCK_IRQSTATE) + switch (mode) { + case HWLOCK_IRQSTATE: ret = spin_trylock_irqsave(&hwlock->lock, *flags); - else if (mode == HWLOCK_IRQ) + break; + case HWLOCK_IRQ: ret = spin_trylock_irq(&hwlock->lock); - else + break; + case HWLOCK_RAW: + ret = 1; + break; + default: ret = spin_trylock(&hwlock->lock); + break; + } /* is lock already taken by another context on the local cpu ? */ if (!ret) @@ -122,12 +128,20 @@ int __hwspin_trylock(struct hwspinlock *hwlock, int mode, unsigned long *flags) /* if hwlock is already taken, undo spin_trylock_* and exit */ if (!ret) { - if (mode == HWLOCK_IRQSTATE) + switch (mode) { + case HWLOCK_IRQSTATE: spin_unlock_irqrestore(&hwlock->lock, *flags); - else if (mode == HWLOCK_IRQ) + break; + case HWLOCK_IRQ: spin_unlock_irq(&hwlock->lock); - else + break; + case HWLOCK_RAW: + /* Nothing to do */ + break; + default: spin_unlock(&hwlock->lock); + break; + } return -EBUSY; } @@ -160,9 +174,14 @@ EXPORT_SYMBOL_GPL(__hwspin_trylock); * is already taken, the function will busy loop waiting for it to * be released, but give up after @timeout msecs have elapsed. * - * Upon a successful return from this function, preemption is disabled - * (and possibly local interrupts, too), so the caller must not sleep, - * and is advised to release the hwspinlock as soon as possible. + * Caution: If the mode is HWLOCK_RAW, that means user must protect the routine + * of getting hardware lock with mutex or spinlock. Since in some scenarios, + * user need some time-consuming or sleepable operations under the hardware + * lock, they need one sleepable lock (like mutex) to protect the operations. + * + * If the mode is not HWLOCK_RAW, upon a successful return from this function, + * preemption is disabled (and possibly local interrupts, too), so the caller + * must not sleep, and is advised to release the hwspinlock as soon as possible. * This is required in order to minimize remote cores polling on the * hardware interconnect. * @@ -249,12 +268,20 @@ void __hwspin_unlock(struct hwspinlock *hwlock, int mode, unsigned long *flags) hwlock->bank->ops->unlock(hwlock); /* Undo the spin_trylock{_irq, _irqsave} called while locking */ - if (mode == HWLOCK_IRQSTATE) + switch (mode) { + case HWLOCK_IRQSTATE: spin_unlock_irqrestore(&hwlock->lock, *flags); - else if (mode == HWLOCK_IRQ) + break; + case HWLOCK_IRQ: spin_unlock_irq(&hwlock->lock); - else + break; + case HWLOCK_RAW: + /* Nothing to do */ + break; + default: spin_unlock(&hwlock->lock); + break; + } } EXPORT_SYMBOL_GPL(__hwspin_unlock); diff --git a/drivers/hwspinlock/hwspinlock_internal.h b/drivers/hwspinlock/hwspinlock_internal.h index d26f78b8f214..9eb6bd020dc7 100644 --- a/drivers/hwspinlock/hwspinlock_internal.h +++ b/drivers/hwspinlock/hwspinlock_internal.h @@ -1,18 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Hardware spinlocks internal header * * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com * * Contact: Ohad Ben-Cohen <ohad@wizery.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __HWSPINLOCK_HWSPINLOCK_H diff --git a/drivers/hwspinlock/omap_hwspinlock.c b/drivers/hwspinlock/omap_hwspinlock.c index d897e5251c36..625844e0abef 100644 --- a/drivers/hwspinlock/omap_hwspinlock.c +++ b/drivers/hwspinlock/omap_hwspinlock.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * OMAP hardware spinlock driver * @@ -6,15 +7,6 @@ * Contact: Simon Que <sque@ti.com> * Hari Kanigeri <h-kanigeri2@ti.com> * Ohad Ben-Cohen <ohad@wizery.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * 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. */ #include <linux/kernel.h> diff --git a/drivers/hwspinlock/qcom_hwspinlock.c b/drivers/hwspinlock/qcom_hwspinlock.c index fa6880b8060a..6da7447d277d 100644 --- a/drivers/hwspinlock/qcom_hwspinlock.c +++ b/drivers/hwspinlock/qcom_hwspinlock.c @@ -1,15 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2013, The Linux Foundation. All rights reserved. * Copyright (c) 2015, Sony Mobile Communications AB - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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. */ #include <linux/hwspinlock.h> diff --git a/drivers/hwspinlock/sirf_hwspinlock.c b/drivers/hwspinlock/sirf_hwspinlock.c index cb38e487c6c4..1f625cd68c50 100644 --- a/drivers/hwspinlock/sirf_hwspinlock.c +++ b/drivers/hwspinlock/sirf_hwspinlock.c @@ -1,9 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SIRF hardware spinlock driver * * Copyright (c) 2015 Cambridge Silicon Radio Limited, a CSR plc group company. - * - * Licensed under GPLv2. */ #include <linux/kernel.h> diff --git a/drivers/hwspinlock/sprd_hwspinlock.c b/drivers/hwspinlock/sprd_hwspinlock.c index 638e64ac18f5..dc42bf51f3e6 100644 --- a/drivers/hwspinlock/sprd_hwspinlock.c +++ b/drivers/hwspinlock/sprd_hwspinlock.c @@ -1,15 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Spreadtrum hardware spinlock driver * Copyright (C) 2017 Spreadtrum - http://www.spreadtrum.com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * 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. */ #include <linux/bitops.h> diff --git a/drivers/hwspinlock/u8500_hsem.c b/drivers/hwspinlock/u8500_hsem.c index 0128d8fb905e..572ca79d77e8 100644 --- a/drivers/hwspinlock/u8500_hsem.c +++ b/drivers/hwspinlock/u8500_hsem.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * u8500 HWSEM driver * @@ -10,15 +11,6 @@ * Simon Que <sque@ti.com> * Hari Kanigeri <h-kanigeri2@ti.com> * Ohad Ben-Cohen <ohad@wizery.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * 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. */ #include <linux/module.h> diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c index 9b6c55523c58..320d29df17e1 100644 --- a/drivers/hwtracing/coresight/coresight-etb10.c +++ b/drivers/hwtracing/coresight/coresight-etb10.c @@ -683,8 +683,8 @@ static int etb_probe(struct amba_device *adev, const struct amba_id *id) if (drvdata->buffer_depth & 0x80000000) return -EINVAL; - drvdata->buf = devm_kzalloc(dev, - drvdata->buffer_depth * 4, GFP_KERNEL); + drvdata->buf = devm_kcalloc(dev, + drvdata->buffer_depth, 4, GFP_KERNEL); if (!drvdata->buf) return -ENOMEM; diff --git a/drivers/hwtracing/coresight/of_coresight.c b/drivers/hwtracing/coresight/of_coresight.c index a33a92ebe74b..6880bee195c8 100644 --- a/drivers/hwtracing/coresight/of_coresight.c +++ b/drivers/hwtracing/coresight/of_coresight.c @@ -71,21 +71,24 @@ static int of_coresight_alloc_memory(struct device *dev, struct coresight_platform_data *pdata) { /* List of output port on this component */ - pdata->outports = devm_kzalloc(dev, pdata->nr_outport * + pdata->outports = devm_kcalloc(dev, + pdata->nr_outport, sizeof(*pdata->outports), GFP_KERNEL); if (!pdata->outports) return -ENOMEM; /* Children connected to this component via @outports */ - pdata->child_names = devm_kzalloc(dev, pdata->nr_outport * + pdata->child_names = devm_kcalloc(dev, + pdata->nr_outport, sizeof(*pdata->child_names), GFP_KERNEL); if (!pdata->child_names) return -ENOMEM; /* Port number on the child this component is connected to */ - pdata->child_ports = devm_kzalloc(dev, pdata->nr_outport * + pdata->child_ports = devm_kcalloc(dev, + pdata->nr_outport, sizeof(*pdata->child_ports), GFP_KERNEL); if (!pdata->child_ports) diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c index 3df0efd69ae3..4a34f311e1ff 100644 --- a/drivers/i2c/algos/i2c-algo-bit.c +++ b/drivers/i2c/algos/i2c-algo-bit.c @@ -519,9 +519,7 @@ static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) } } } else { /* normal 7bit address */ - addr = msg->addr << 1; - if (flags & I2C_M_RD) - addr |= 1; + addr = i2c_8bit_addr_from_msg(msg); if (flags & I2C_M_REV_DIR_ADDR) addr ^= 1; ret = try_address(i2c_adap, addr, retries); diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c index e370804ec8bc..883a290f6a4d 100644 --- a/drivers/i2c/algos/i2c-algo-pca.c +++ b/drivers/i2c/algos/i2c-algo-pca.c @@ -112,11 +112,8 @@ static int pca_address(struct i2c_algo_pca_data *adap, struct i2c_msg *msg) { int sta = pca_get_con(adap); - int addr; + int addr = i2c_8bit_addr_from_msg(msg); - addr = ((0x7f & msg->addr) << 1); - if (msg->flags & I2C_M_RD) - addr |= 1; DEB2("=== SLAVE ADDRESS %#04x+%c=%#04x\n", msg->addr, msg->flags & I2C_M_RD ? 'R' : 'W', addr); diff --git a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c index 270d84bfc2c6..5c29a4d397cf 100644 --- a/drivers/i2c/algos/i2c-algo-pcf.c +++ b/drivers/i2c/algos/i2c-algo-pcf.c @@ -291,13 +291,9 @@ static int pcf_readbytes(struct i2c_adapter *i2c_adap, char *buf, static int pcf_doAddress(struct i2c_algo_pcf_data *adap, struct i2c_msg *msg) { - unsigned short flags = msg->flags; - unsigned char addr; + unsigned char addr = i2c_8bit_addr_from_msg(msg); - addr = msg->addr << 1; - if (flags & I2C_M_RD) - addr |= 1; - if (flags & I2C_M_REV_DIR_ADDR) + if (msg->flags & I2C_M_REV_DIR_ADDR) addr ^= 1; i2c_outb(adap, addr); diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index fce9f2ca0570..4f8df2ec87b1 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -943,6 +943,7 @@ config I2C_STM32F4 config I2C_STM32F7 tristate "STMicroelectronics STM32F7 I2C support" depends on ARCH_STM32 || COMPILE_TEST + select I2C_SLAVE help Enable this option to add support for STM32 I2C controller embedded in STM32F7 SoCs. diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 189e34ba050f..5a869144a0c5 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -94,7 +94,8 @@ obj-$(CONFIG_I2C_SIRF) += i2c-sirf.o obj-$(CONFIG_I2C_SPRD) += i2c-sprd.o obj-$(CONFIG_I2C_ST) += i2c-st.o obj-$(CONFIG_I2C_STM32F4) += i2c-stm32f4.o -obj-$(CONFIG_I2C_STM32F7) += i2c-stm32f7.o +i2c-stm32f7-drv-objs := i2c-stm32f7.o i2c-stm32.o +obj-$(CONFIG_I2C_STM32F7) += i2c-stm32f7-drv.o obj-$(CONFIG_I2C_STU300) += i2c-stu300.o obj-$(CONFIG_I2C_SUN6I_P2WI) += i2c-sun6i-p2wi.o obj-$(CONFIG_I2C_SYNQUACER) += i2c-synquacer.o diff --git a/drivers/i2c/busses/i2c-amd756-s4882.c b/drivers/i2c/busses/i2c-amd756-s4882.c index 65e324054970..a2f5f992af7a 100644 --- a/drivers/i2c/busses/i2c-amd756-s4882.c +++ b/drivers/i2c/busses/i2c-amd756-s4882.c @@ -169,12 +169,12 @@ static int __init amd756_s4882_init(void) printk(KERN_INFO "Enabling SMBus multiplexing for Tyan S4882\n"); /* Define the 5 virtual adapters and algorithms structures */ - if (!(s4882_adapter = kzalloc(5 * sizeof(struct i2c_adapter), + if (!(s4882_adapter = kcalloc(5, sizeof(struct i2c_adapter), GFP_KERNEL))) { error = -ENOMEM; goto ERROR1; } - if (!(s4882_algo = kzalloc(5 * sizeof(struct i2c_algorithm), + if (!(s4882_algo = kcalloc(5, sizeof(struct i2c_algorithm), GFP_KERNEL))) { error = -ENOMEM; goto ERROR2; diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c index 7d4aeb4465b3..60e4d0e939a3 100644 --- a/drivers/i2c/busses/i2c-aspeed.c +++ b/drivers/i2c/busses/i2c-aspeed.c @@ -335,13 +335,12 @@ static void aspeed_i2c_do_start(struct aspeed_i2c_bus *bus) { u32 command = ASPEED_I2CD_M_START_CMD | ASPEED_I2CD_M_TX_CMD; struct i2c_msg *msg = &bus->msgs[bus->msgs_index]; - u8 slave_addr = msg->addr << 1; + u8 slave_addr = i2c_8bit_addr_from_msg(msg); bus->master_state = ASPEED_I2C_MASTER_START; bus->buf_index = 0; if (msg->flags & I2C_M_RD) { - slave_addr |= 1; command |= ASPEED_I2CD_M_RX_CMD; /* Need to let the hardware know to NACK after RX. */ if (msg->len == 1 && !(msg->flags & I2C_M_RECV_LEN)) diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index bfd1fdff64a9..3f3e8b3bf5ff 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -518,8 +518,16 @@ static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id) * the RXRDY interrupt first in order to not keep garbage data in the * Receive Holding Register for the next transfer. */ - if (irqstatus & AT91_TWI_RXRDY) - at91_twi_read_next_byte(dev); + if (irqstatus & AT91_TWI_RXRDY) { + /* + * Read all available bytes at once by polling RXRDY usable w/ + * and w/o FIFO. With FIFO enabled we could also read RXFL and + * avoid polling RXRDY. + */ + do { + at91_twi_read_next_byte(dev); + } while (at91_twi_read(dev, AT91_TWI_SR) & AT91_TWI_RXRDY); + } /* * When a NACK condition is detected, the I2C controller sets the NACK, diff --git a/drivers/i2c/busses/i2c-axxia.c b/drivers/i2c/busses/i2c-axxia.c index 13f07482ec68..8e60048a33f8 100644 --- a/drivers/i2c/busses/i2c-axxia.c +++ b/drivers/i2c/busses/i2c-axxia.c @@ -351,13 +351,15 @@ static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg) * addr_2: addr[7:0] */ addr_1 = 0xF0 | ((msg->addr >> 7) & 0x06); + if (i2c_m_rd(msg)) + addr_1 |= 1; /* Set the R/nW bit of the address */ addr_2 = msg->addr & 0xFF; } else { /* 7-bit address * addr_1: addr[6:0] | (R/nW) * addr_2: dont care */ - addr_1 = (msg->addr << 1) & 0xFF; + addr_1 = i2c_8bit_addr_from_msg(msg); addr_2 = 0; } @@ -365,7 +367,6 @@ static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg) /* I2C read transfer */ rx_xfer = i2c_m_recv_len(msg) ? I2C_SMBUS_BLOCK_MAX : msg->len; tx_xfer = 0; - addr_1 |= 1; /* Set the R/nW bit of the address */ } else { /* I2C write transfer */ rx_xfer = 0; @@ -532,23 +533,23 @@ static int axxia_i2c_probe(struct platform_device *pdev) if (idev->bus_clk_rate == 0) idev->bus_clk_rate = 100000; /* default clock rate */ + ret = clk_prepare_enable(idev->i2c_clk); + if (ret) { + dev_err(&pdev->dev, "failed to enable clock\n"); + return ret; + } + ret = axxia_i2c_init(idev); if (ret) { dev_err(&pdev->dev, "failed to initialize\n"); - return ret; + goto error_disable_clk; } ret = devm_request_irq(&pdev->dev, irq, axxia_i2c_isr, 0, pdev->name, idev); if (ret) { dev_err(&pdev->dev, "failed to claim IRQ%d\n", irq); - return ret; - } - - ret = clk_prepare_enable(idev->i2c_clk); - if (ret) { - dev_err(&pdev->dev, "failed to enable clock\n"); - return ret; + goto error_disable_clk; } i2c_set_adapdata(&idev->adapter, idev); @@ -563,12 +564,14 @@ static int axxia_i2c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, idev); ret = i2c_add_adapter(&idev->adapter); - if (ret) { - clk_disable_unprepare(idev->i2c_clk); - return ret; - } + if (ret) + goto error_disable_clk; return 0; + +error_disable_clk: + clk_disable_unprepare(idev->i2c_clk); + return ret; } static int axxia_i2c_remove(struct platform_device *pdev) diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c index 27ebd90de43b..48914dfc8ce8 100644 --- a/drivers/i2c/busses/i2c-designware-common.c +++ b/drivers/i2c/busses/i2c-designware-common.c @@ -149,18 +149,17 @@ u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset) return ((ic_clk * (tLOW + tf) + 500000) / 1000000) - 1 + offset; } -void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable) -{ - dw_writel(dev, enable, DW_IC_ENABLE); -} - -void __i2c_dw_enable_and_wait(struct dw_i2c_dev *dev, bool enable) +void __i2c_dw_disable(struct dw_i2c_dev *dev) { int timeout = 100; do { - __i2c_dw_enable(dev, enable); - if ((dw_readl(dev, DW_IC_ENABLE_STATUS) & 1) == enable) + __i2c_dw_disable_nowait(dev); + /* + * The enable status register may be unimplemented, but + * in that case this test reads zero and exits the loop. + */ + if ((dw_readl(dev, DW_IC_ENABLE_STATUS) & 1) == 0) return; /* @@ -171,8 +170,7 @@ void __i2c_dw_enable_and_wait(struct dw_i2c_dev *dev, bool enable) usleep_range(25, 250); } while (timeout--); - dev_warn(dev->dev, "timeout in %sabling adapter\n", - enable ? "en" : "dis"); + dev_warn(dev->dev, "timeout in disabling adapter\n"); } unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev) @@ -277,7 +275,7 @@ u32 i2c_dw_func(struct i2c_adapter *adap) void i2c_dw_disable(struct dw_i2c_dev *dev) { /* Disable controller */ - __i2c_dw_enable_and_wait(dev, false); + __i2c_dw_disable(dev); /* Disable all interupts */ dw_writel(dev, 0, DW_IC_INTR_MASK); diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index 8707c76b2fee..d690e648bc01 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -297,8 +297,6 @@ u32 dw_readl(struct dw_i2c_dev *dev, int offset); void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset); u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset); u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset); -void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable); -void __i2c_dw_enable_and_wait(struct dw_i2c_dev *dev, bool enable); unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev); int i2c_dw_prepare_clk(struct dw_i2c_dev *dev, bool prepare); int i2c_dw_acquire_lock(struct dw_i2c_dev *dev); @@ -309,6 +307,18 @@ u32 i2c_dw_func(struct i2c_adapter *adap); void i2c_dw_disable(struct dw_i2c_dev *dev); void i2c_dw_disable_int(struct dw_i2c_dev *dev); +static inline void __i2c_dw_enable(struct dw_i2c_dev *dev) +{ + dw_writel(dev, 1, DW_IC_ENABLE); +} + +static inline void __i2c_dw_disable_nowait(struct dw_i2c_dev *dev) +{ + dw_writel(dev, 0, DW_IC_ENABLE); +} + +void __i2c_dw_disable(struct dw_i2c_dev *dev); + extern u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev); extern int i2c_dw_probe(struct dw_i2c_dev *dev); #if IS_ENABLED(CONFIG_I2C_DESIGNWARE_SLAVE) diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c index 0cdba29ae0a9..27436a937492 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -81,7 +81,7 @@ static int i2c_dw_init_master(struct dw_i2c_dev *dev) comp_param1 = dw_readl(dev, DW_IC_COMP_PARAM_1); /* Disable the adapter */ - __i2c_dw_enable_and_wait(dev, false); + __i2c_dw_disable(dev); /* Set standard and fast speed deviders for high/low periods */ @@ -180,7 +180,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev) u32 ic_con, ic_tar = 0; /* Disable the adapter */ - __i2c_dw_enable_and_wait(dev, false); + __i2c_dw_disable(dev); /* If the slave address is ten bit address, enable 10BITADDR */ ic_con = dw_readl(dev, DW_IC_CON); @@ -209,7 +209,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev) i2c_dw_disable_int(dev); /* Enable the adapter */ - __i2c_dw_enable(dev, true); + __i2c_dw_enable(dev); /* Dummy read to avoid the register getting stuck on Bay Trail */ dw_readl(dev, DW_IC_ENABLE_STATUS); @@ -462,7 +462,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) * additional interrupts are a hardware bug or this driver doesn't * handle them correctly yet. */ - __i2c_dw_enable(dev, false); + __i2c_dw_disable_nowait(dev); if (dev->msg_err) { ret = dev->msg_err; diff --git a/drivers/i2c/busses/i2c-designware-slave.c b/drivers/i2c/busses/i2c-designware-slave.c index d42558d1b002..8ce2cd368477 100644 --- a/drivers/i2c/busses/i2c-designware-slave.c +++ b/drivers/i2c/busses/i2c-designware-slave.c @@ -75,7 +75,7 @@ static int i2c_dw_init_slave(struct dw_i2c_dev *dev) comp_param1 = dw_readl(dev, DW_IC_COMP_PARAM_1); /* Disable the adapter. */ - __i2c_dw_enable_and_wait(dev, false); + __i2c_dw_disable(dev); /* Configure SDA Hold Time if required. */ reg = dw_readl(dev, DW_IC_COMP_VERSION); @@ -119,11 +119,11 @@ static int i2c_dw_reg_slave(struct i2c_client *slave) * Set slave address in the IC_SAR register, * the address to which the DW_apb_i2c responds. */ - __i2c_dw_enable(dev, false); + __i2c_dw_disable_nowait(dev); dw_writel(dev, slave->addr, DW_IC_SAR); dev->slave = slave; - __i2c_dw_enable(dev, true); + __i2c_dw_enable(dev); dev->cmd_err = 0; dev->msg_write_idx = 0; diff --git a/drivers/i2c/busses/i2c-diolan-u2c.c b/drivers/i2c/busses/i2c-diolan-u2c.c index f718ee4e3332..3f28317cde39 100644 --- a/drivers/i2c/busses/i2c-diolan-u2c.c +++ b/drivers/i2c/busses/i2c-diolan-u2c.c @@ -360,11 +360,11 @@ static int diolan_usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, if (ret < 0) goto abort; } + ret = diolan_i2c_put_byte_ack(dev, + i2c_8bit_addr_from_msg(pmsg)); + if (ret < 0) + goto abort; if (pmsg->flags & I2C_M_RD) { - ret = - diolan_i2c_put_byte_ack(dev, (pmsg->addr << 1) | 1); - if (ret < 0) - goto abort; for (j = 0; j < pmsg->len; j++) { u8 byte; bool ack = j < pmsg->len - 1; @@ -393,9 +393,6 @@ static int diolan_usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, pmsg->buf[j] = byte; } } else { - ret = diolan_i2c_put_byte_ack(dev, pmsg->addr << 1); - if (ret < 0) - goto abort; for (j = 0; j < pmsg->len; j++) { ret = diolan_i2c_put_byte_ack(dev, pmsg->buf[j]); diff --git a/drivers/i2c/busses/i2c-efm32.c b/drivers/i2c/busses/i2c-efm32.c index aa336ba89aa3..5f2bab878b2c 100644 --- a/drivers/i2c/busses/i2c-efm32.c +++ b/drivers/i2c/busses/i2c-efm32.c @@ -144,8 +144,7 @@ static void efm32_i2c_send_next_msg(struct efm32_i2c_ddata *ddata) struct i2c_msg *cur_msg = &ddata->msgs[ddata->current_msg]; efm32_i2c_write32(ddata, REG_CMD, REG_CMD_START); - efm32_i2c_write32(ddata, REG_TXDATA, cur_msg->addr << 1 | - (cur_msg->flags & I2C_M_RD ? 1 : 0)); + efm32_i2c_write32(ddata, REG_TXDATA, i2c_8bit_addr_from_msg(cur_msg)); } static void efm32_i2c_send_next_byte(struct efm32_i2c_ddata *ddata) diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c index bdeab0174fec..835d54ac2971 100644 --- a/drivers/i2c/busses/i2c-eg20t.c +++ b/drivers/i2c/busses/i2c-eg20t.c @@ -414,7 +414,7 @@ static s32 pch_i2c_writebytes(struct i2c_adapter *i2c_adap, iowrite32(addr_8_lsb, p + PCH_I2CDR); } else { /* set 7 bit slave address and R/W bit as 0 */ - iowrite32(addr << 1, p + PCH_I2CDR); + iowrite32(i2c_8bit_addr_from_msg(msgs), p + PCH_I2CDR); if (first) pch_i2c_start(adap); } @@ -538,8 +538,7 @@ static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR); } else { /* 7 address bits + R/W bit */ - addr = (((addr) << 1) | (I2C_RD)); - iowrite32(addr, p + PCH_I2CDR); + iowrite32(i2c_8bit_addr_from_msg(msgs), p + PCH_I2CDR); } /* check if it is the first message */ diff --git a/drivers/i2c/busses/i2c-emev2.c b/drivers/i2c/busses/i2c-emev2.c index d2e84480fbe9..ba9b6ea48a31 100644 --- a/drivers/i2c/busses/i2c-emev2.c +++ b/drivers/i2c/busses/i2c-emev2.c @@ -149,7 +149,7 @@ static int __em_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, em_clear_set_bit(priv, 0, I2C_BIT_STT0, I2C_OFS_IICC0); /* Send slave address and R/W type */ - writeb((msg->addr << 1) | read, priv->base + I2C_OFS_IIC0); + writeb(i2c_8bit_addr_from_msg(msg), priv->base + I2C_OFS_IIC0); /* Wait for transaction */ status = em_i2c_wait_for_event(priv); diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index 12ec8484e653..de82ad8ff534 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -707,7 +707,7 @@ static int exynos5_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { struct exynos5_i2c *i2c = adap->algo_data; - int i = 0, ret = 0, stop = 0; + int i, ret; if (i2c->suspended) { dev_err(i2c->dev, "HS-I2C is not initialized.\n"); @@ -718,30 +718,15 @@ static int exynos5_i2c_xfer(struct i2c_adapter *adap, if (ret) return ret; - for (i = 0; i < num; i++, msgs++) { - stop = (i == num - 1); - - ret = exynos5_i2c_xfer_msg(i2c, msgs, stop); - - if (ret < 0) - goto out; - } - - if (i == num) { - ret = num; - } else { - /* Only one message, cannot access the device */ - if (i == 1) - ret = -EREMOTEIO; - else - ret = i; - - dev_warn(i2c->dev, "xfer message failed\n"); + for (i = 0; i < num; ++i) { + ret = exynos5_i2c_xfer_msg(i2c, msgs + i, i + 1 == num); + if (ret) + break; } - out: clk_disable(i2c->clk); - return ret; + + return ret ?: num; } static u32 exynos5_i2c_func(struct i2c_adapter *adap) diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index 58abb3eced58..005e6e0330c2 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -11,7 +11,7 @@ #include <linux/delay.h> #include <linux/i2c.h> #include <linux/i2c-algo-bit.h> -#include <linux/i2c-gpio.h> +#include <linux/platform_data/i2c-gpio.h> #include <linux/init.h> #include <linux/module.h> #include <linux/slab.h> diff --git a/drivers/i2c/busses/i2c-hix5hd2.c b/drivers/i2c/busses/i2c-hix5hd2.c index bb68957d3da5..061a4bfb03f4 100644 --- a/drivers/i2c/busses/i2c-hix5hd2.c +++ b/drivers/i2c/busses/i2c-hix5hd2.c @@ -73,7 +73,6 @@ #define I2C_OVER_INTR BIT(0) #define HIX5I2C_MAX_FREQ 400000 /* 400k */ -#define HIX5I2C_READ_OPERATION 0x01 enum hix5hd2_i2c_state { HIX5I2C_STAT_RW_ERR = -1, @@ -311,12 +310,8 @@ static void hix5hd2_i2c_message_start(struct hix5hd2_i2c_priv *priv, int stop) hix5hd2_i2c_clr_all_irq(priv); hix5hd2_i2c_enable_irq(priv); - if (priv->msg->flags & I2C_M_RD) - writel_relaxed((priv->msg->addr << 1) | HIX5I2C_READ_OPERATION, - priv->regs + HIX5I2C_TXR); - else - writel_relaxed(priv->msg->addr << 1, - priv->regs + HIX5I2C_TXR); + writel_relaxed(i2c_8bit_addr_from_msg(priv->msg), + priv->regs + HIX5I2C_TXR); writel_relaxed(I2C_WRITE | I2C_START, priv->regs + HIX5I2C_COM); spin_unlock_irqrestore(&priv->lock, flags); @@ -377,17 +372,7 @@ static int hix5hd2_i2c_xfer(struct i2c_adapter *adap, goto out; } - if (i == num) { - ret = num; - } else { - /* Only one message, cannot access the device */ - if (i == 1) - ret = -EREMOTEIO; - else - ret = i; - - dev_warn(priv->dev, "xfer message failed\n"); - } + ret = num; out: pm_runtime_mark_last_busy(priv->dev); @@ -471,7 +456,6 @@ static int hix5hd2_i2c_probe(struct platform_device *pdev) goto err_clk; } - pm_suspend_ignore_children(&pdev->dev, true); pm_runtime_set_autosuspend_delay(priv->dev, MSEC_PER_SEC); pm_runtime_use_autosuspend(priv->dev); pm_runtime_set_active(priv->dev); diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index e0d59e9ff3c6..aa726607645e 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -106,7 +106,7 @@ #if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI #include <linux/gpio.h> -#include <linux/i2c-mux-gpio.h> +#include <linux/platform_data/i2c-mux-gpio.h> #endif /* I801 SMBus address offsets */ @@ -1710,7 +1710,7 @@ static void i801_shutdown(struct pci_dev *dev) pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg); } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int i801_suspend(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); @@ -1731,8 +1731,7 @@ static int i801_resume(struct device *dev) } #endif -static UNIVERSAL_DEV_PM_OPS(i801_pm_ops, i801_suspend, - i801_resume, NULL); +static SIMPLE_DEV_PM_OPS(i801_pm_ops, i801_suspend, i801_resume); static struct pci_driver i801_driver = { .name = "i801_smbus", diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index 961c5f42d956..6f6e1dfe7cce 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -561,9 +561,6 @@ static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) DBG2("%d: iic_xfer, %d msg(s)\n", dev->idx, num); - if (!num) - return 0; - /* Check the sanity of the passed messages. * Uhh, generic i2c layer is more suitable place for such code... */ diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c index e6da2c7a9a3e..6d975f5221ca 100644 --- a/drivers/i2c/busses/i2c-imx-lpi2c.c +++ b/drivers/i2c/busses/i2c-imx-lpi2c.c @@ -1,18 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * This is i.MX low power i2c controller 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. - * */ #include <linux/clk.h> @@ -180,15 +170,13 @@ static int lpi2c_imx_start(struct lpi2c_imx_struct *lpi2c_imx, struct i2c_msg *msgs) { unsigned int temp; - u8 read; temp = readl(lpi2c_imx->base + LPI2C_MCR); temp |= MCR_RRF | MCR_RTF; writel(temp, lpi2c_imx->base + LPI2C_MCR); writel(0x7f00, lpi2c_imx->base + LPI2C_MSR); - read = msgs->flags & I2C_M_RD; - temp = (msgs->addr << 1 | read) | (GEN_START << 8); + temp = i2c_8bit_addr_from_msg(msgs) | (GEN_START << 8); writel(temp, lpi2c_imx->base + LPI2C_MTDR); return lpi2c_imx_bus_busy(lpi2c_imx); diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index d7267dd9c7bf..0207e194f84b 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -1,16 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2002 Motorola GSG-China * - * 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. - * * Author: * Darius Augulis, Teltonika Inc. * @@ -630,7 +621,7 @@ static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx, * Write slave address. * The first byte must be transmitted by the CPU. */ - imx_i2c_write_reg(msgs->addr << 1, i2c_imx, IMX_I2C_I2DR); + imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR); reinit_completion(&i2c_imx->dma->cmd_complete); time_left = wait_for_completion_timeout( &i2c_imx->dma->cmd_complete, @@ -760,10 +751,10 @@ static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs) int i, result; dev_dbg(&i2c_imx->adapter.dev, "<%s> write slave address: addr=0x%x\n", - __func__, msgs->addr << 1); + __func__, i2c_8bit_addr_from_msg(msgs)); /* write slave address */ - imx_i2c_write_reg(msgs->addr << 1, i2c_imx, IMX_I2C_I2DR); + imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR); result = i2c_imx_trx_complete(i2c_imx); if (result) return result; @@ -796,10 +787,10 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bo dev_dbg(&i2c_imx->adapter.dev, "<%s> write slave address: addr=0x%x\n", - __func__, (msgs->addr << 1) | 0x01); + __func__, i2c_8bit_addr_from_msg(msgs)); /* write slave address */ - imx_i2c_write_reg((msgs->addr << 1) | 0x01, i2c_imx, IMX_I2C_I2DR); + imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR); result = i2c_imx_trx_complete(i2c_imx); if (result) return result; diff --git a/drivers/i2c/busses/i2c-kempld.c b/drivers/i2c/busses/i2c-kempld.c index e879190b5d1d..1c874aaa0447 100644 --- a/drivers/i2c/busses/i2c-kempld.c +++ b/drivers/i2c/busses/i2c-kempld.c @@ -124,15 +124,14 @@ static int kempld_i2c_process(struct kempld_i2c_data *i2c) /* 10 bit address? */ if (i2c->msg->flags & I2C_M_TEN) { addr = 0xf0 | ((i2c->msg->addr >> 7) & 0x6); + /* Set read bit if necessary */ + addr |= (i2c->msg->flags & I2C_M_RD) ? 1 : 0; i2c->state = STATE_ADDR10; } else { - addr = (i2c->msg->addr << 1); + addr = i2c_8bit_addr_from_msg(i2c->msg); i2c->state = STATE_START; } - /* Set read bit if necessary */ - addr |= (i2c->msg->flags & I2C_M_RD) ? 1 : 0; - kempld_write8(pld, KEMPLD_I2C_DATA, addr); kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_START); diff --git a/drivers/i2c/busses/i2c-mlxcpld.c b/drivers/i2c/busses/i2c-mlxcpld.c index 4c28fa28ce76..745ed43a22d6 100644 --- a/drivers/i2c/busses/i2c-mlxcpld.c +++ b/drivers/i2c/busses/i2c-mlxcpld.c @@ -45,13 +45,16 @@ #define MLXCPLD_I2C_VALID_FLAG (I2C_M_RECV_LEN | I2C_M_RD) #define MLXCPLD_I2C_BUS_NUM 1 #define MLXCPLD_I2C_DATA_REG_SZ 36 +#define MLXCPLD_I2C_DATA_SZ_BIT BIT(5) +#define MLXCPLD_I2C_DATA_SZ_MASK GENMASK(6, 5) +#define MLXCPLD_I2C_SMBUS_BLK_BIT BIT(7) #define MLXCPLD_I2C_MAX_ADDR_LEN 4 #define MLXCPLD_I2C_RETR_NUM 2 #define MLXCPLD_I2C_XFER_TO 500000 /* usec */ #define MLXCPLD_I2C_POLL_TIME 2000 /* usec */ /* LPC I2C registers */ -#define MLXCPLD_LPCI2C_LPF_REG 0x0 +#define MLXCPLD_LPCI2C_CPBLTY_REG 0x0 #define MLXCPLD_LPCI2C_CTRL_REG 0x1 #define MLXCPLD_LPCI2C_HALF_CYC_REG 0x4 #define MLXCPLD_LPCI2C_I2C_HOLD_REG 0x5 @@ -83,6 +86,7 @@ struct mlxcpld_i2c_priv { struct mutex lock; struct mlxcpld_i2c_curr_xfer xfer; struct device *dev; + bool smbus_block; }; static void mlxcpld_i2c_lpc_write_buf(u8 *data, u8 len, u32 addr) @@ -230,7 +234,7 @@ static void mlxcpld_i2c_set_transf_data(struct mlxcpld_i2c_priv *priv, * All upper layers currently are never use transfer with more than * 2 messages. Actually, it's also not so relevant in Mellanox systems * because of HW limitation. Max size of transfer is not more than 32 - * bytes in the current x86 LPCI2C bridge. + * or 68 bytes in the current x86 LPCI2C bridge. */ priv->xfer.cmd = msgs[num - 1].flags & I2C_M_RD; @@ -295,7 +299,7 @@ static int mlxcpld_i2c_wait_for_free(struct mlxcpld_i2c_priv *priv) static int mlxcpld_i2c_wait_for_tc(struct mlxcpld_i2c_priv *priv) { int status, i, timeout = 0; - u8 datalen; + u8 datalen, val; do { usleep_range(MLXCPLD_I2C_POLL_TIME / 2, MLXCPLD_I2C_POLL_TIME); @@ -324,9 +328,22 @@ static int mlxcpld_i2c_wait_for_tc(struct mlxcpld_i2c_priv *priv) * Actual read data len will be always the same as * requested len. 0xff (line pull-up) will be returned * if slave has no data to return. Thus don't read - * MLXCPLD_LPCI2C_NUM_DAT_REG reg from CPLD. + * MLXCPLD_LPCI2C_NUM_DAT_REG reg from CPLD. Only in case of + * SMBus block read transaction data len can be different, + * check this case. */ - datalen = priv->xfer.data_len; + mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_NUM_ADDR_REG, &val, + 1); + if (priv->smbus_block && (val & MLXCPLD_I2C_SMBUS_BLK_BIT)) { + mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_NUM_DAT_REG, + &datalen, 1); + if (unlikely(datalen > (I2C_SMBUS_BLOCK_MAX + 1))) { + dev_err(priv->dev, "Incorrect smbus block read message len\n"); + return -E2BIG; + } + } else { + datalen = priv->xfer.data_len; + } mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_DATA_REG, priv->xfer.msg[i].buf, datalen); @@ -344,12 +361,20 @@ static int mlxcpld_i2c_wait_for_tc(struct mlxcpld_i2c_priv *priv) static void mlxcpld_i2c_xfer_msg(struct mlxcpld_i2c_priv *priv) { int i, len = 0; - u8 cmd; + u8 cmd, val; mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_NUM_DAT_REG, &priv->xfer.data_len, 1); - mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_NUM_ADDR_REG, - &priv->xfer.addr_width, 1); + + val = priv->xfer.addr_width; + /* Notify HW about SMBus block read transaction */ + if (priv->smbus_block && priv->xfer.msg_num >= 2 && + priv->xfer.msg[1].len == 1 && + (priv->xfer.msg[1].flags & I2C_M_RECV_LEN) && + (priv->xfer.msg[1].flags & I2C_M_RD)) + val |= MLXCPLD_I2C_SMBUS_BLK_BIT; + + mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_NUM_ADDR_REG, &val, 1); for (i = 0; i < priv->xfer.msg_num; i++) { if ((priv->xfer.msg[i].flags & I2C_M_RD) != I2C_M_RD) { @@ -425,7 +450,14 @@ static int mlxcpld_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, static u32 mlxcpld_i2c_func(struct i2c_adapter *adap) { - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_BLOCK_DATA; + struct mlxcpld_i2c_priv *priv = i2c_get_adapdata(adap); + + if (priv->smbus_block) + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | + I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_BLOCK_DATA; + else + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | + I2C_FUNC_SMBUS_I2C_BLOCK; } static const struct i2c_algorithm mlxcpld_i2c_algo = { @@ -440,6 +472,13 @@ static const struct i2c_adapter_quirks mlxcpld_i2c_quirks = { .max_comb_1st_msg_len = 4, }; +static const struct i2c_adapter_quirks mlxcpld_i2c_quirks_ext = { + .flags = I2C_AQ_COMB_WRITE_THEN_READ, + .max_read_len = MLXCPLD_I2C_DATA_REG_SZ * 2 - MLXCPLD_I2C_MAX_ADDR_LEN, + .max_write_len = MLXCPLD_I2C_DATA_REG_SZ * 2, + .max_comb_1st_msg_len = 4, +}; + static struct i2c_adapter mlxcpld_i2c_adapter = { .owner = THIS_MODULE, .name = "i2c-mlxcpld", @@ -454,6 +493,7 @@ static int mlxcpld_i2c_probe(struct platform_device *pdev) { struct mlxcpld_i2c_priv *priv; int err; + u8 val; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -466,6 +506,16 @@ static int mlxcpld_i2c_probe(struct platform_device *pdev) /* Register with i2c layer */ mlxcpld_i2c_adapter.timeout = usecs_to_jiffies(MLXCPLD_I2C_XFER_TO); + /* Read capability register */ + mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_CPBLTY_REG, &val, 1); + /* Check support for extended transaction length */ + if ((val & MLXCPLD_I2C_DATA_SZ_MASK) == MLXCPLD_I2C_DATA_SZ_BIT) + mlxcpld_i2c_adapter.quirks = &mlxcpld_i2c_quirks_ext; + /* Check support for smbus block transaction */ + if (val & MLXCPLD_I2C_SMBUS_BLK_BIT) + priv->smbus_block = true; + if (pdev->id >= -1) + mlxcpld_i2c_adapter.nr = pdev->id; priv->adap = mlxcpld_i2c_adapter; priv->adap.dev.parent = &pdev->dev; priv->base_addr = MLXPLAT_CPLD_LPC_I2C_BASE_ADDR; diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c index cf23a746cc17..1e57f58fcb00 100644 --- a/drivers/i2c/busses/i2c-mt65xx.c +++ b/drivers/i2c/busses/i2c-mt65xx.c @@ -27,6 +27,7 @@ #include <linux/mm.h> #include <linux/module.h> #include <linux/of_address.h> +#include <linux/of_device.h> #include <linux/of_irq.h> #include <linux/platform_device.h> #include <linux/scatterlist.h> @@ -734,7 +735,6 @@ static int mtk_i2c_parse_dt(struct device_node *np, struct mtk_i2c *i2c) static int mtk_i2c_probe(struct platform_device *pdev) { - const struct of_device_id *of_id; int ret = 0; struct mtk_i2c *i2c; struct clk *clk; @@ -761,11 +761,7 @@ static int mtk_i2c_probe(struct platform_device *pdev) init_completion(&i2c->msg_complete); - of_id = of_match_node(mtk_i2c_of_match, pdev->dev.of_node); - if (!of_id) - return -EINVAL; - - i2c->dev_comp = of_id->data; + i2c->dev_comp = of_device_get_match_data(&pdev->dev); i2c->adap.dev.of_node = pdev->dev.of_node; i2c->dev = &pdev->dev; i2c->adap.dev.parent = &pdev->dev; diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index e617bd600794..642c58946d8d 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Freescale MXS I2C bus driver * @@ -7,12 +8,6 @@ * based on a (non-working) driver which was: * * Copyright (C) 2009-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. - * */ #include <linux/slab.h> @@ -180,9 +175,10 @@ static int mxs_i2c_dma_setup_xfer(struct i2c_adapter *adap, struct dma_async_tx_descriptor *desc; struct mxs_i2c_dev *i2c = i2c_get_adapdata(adap); + i2c->addr_data = i2c_8bit_addr_from_msg(msg); + if (msg->flags & I2C_M_RD) { i2c->dma_read = true; - i2c->addr_data = (msg->addr << 1) | I2C_SMBUS_READ; /* * SELECT command. @@ -240,7 +236,6 @@ static int mxs_i2c_dma_setup_xfer(struct i2c_adapter *adap, } } else { i2c->dma_read = false; - i2c->addr_data = (msg->addr << 1) | I2C_SMBUS_WRITE; /* * WRITE command. @@ -371,7 +366,7 @@ static int mxs_i2c_pio_setup_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, uint32_t flags) { struct mxs_i2c_dev *i2c = i2c_get_adapdata(adap); - uint32_t addr_data = msg->addr << 1; + uint32_t addr_data = i2c_8bit_addr_from_msg(msg); uint32_t data = 0; int i, ret, xlen = 0, xmit = 0; uint32_t start; @@ -411,8 +406,6 @@ static int mxs_i2c_pio_setup_xfer(struct i2c_adapter *adap, */ BUG_ON(msg->len > 4); - addr_data |= I2C_SMBUS_READ; - /* SELECT command. */ mxs_i2c_pio_trigger_write_cmd(i2c, MXS_CMD_I2C_SELECT, addr_data); @@ -450,7 +443,6 @@ static int mxs_i2c_pio_setup_xfer(struct i2c_adapter *adap, * fast enough. It is possible to transfer arbitrary amount * of data using PIO write. */ - addr_data |= I2C_SMBUS_WRITE; /* * The LSB of data buffer is the first byte blasted across diff --git a/drivers/i2c/busses/i2c-nforce2-s4985.c b/drivers/i2c/busses/i2c-nforce2-s4985.c index 88eda09e73c0..58a0fbf0e074 100644 --- a/drivers/i2c/busses/i2c-nforce2-s4985.c +++ b/drivers/i2c/busses/i2c-nforce2-s4985.c @@ -164,12 +164,12 @@ static int __init nforce2_s4985_init(void) printk(KERN_INFO "Enabling SMBus multiplexing for Tyan S4985\n"); /* Define the 5 virtual adapters and algorithms structures */ - s4985_adapter = kzalloc(5 * sizeof(struct i2c_adapter), GFP_KERNEL); + s4985_adapter = kcalloc(5, sizeof(struct i2c_adapter), GFP_KERNEL); if (!s4985_adapter) { error = -ENOMEM; goto ERROR1; } - s4985_algo = kzalloc(5 * sizeof(struct i2c_algorithm), GFP_KERNEL); + s4985_algo = kcalloc(5, sizeof(struct i2c_algorithm), GFP_KERNEL); if (!s4985_algo) { error = -ENOMEM; goto ERROR2; diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index 3241bb9d6c18..f6a1272c5854 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -381,7 +381,7 @@ static int nforce2_probe(struct pci_dev *dev, const struct pci_device_id *id) int res1, res2; /* we support 2 SMBus adapters */ - smbuses = kzalloc(2 * sizeof(struct nforce2_smbus), GFP_KERNEL); + smbuses = kcalloc(2, sizeof(struct nforce2_smbus), GFP_KERNEL); if (!smbuses) return -ENOMEM; pci_set_drvdata(dev, smbuses); diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index 49c7c0c91486..0ed5a41804dc 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -1012,8 +1012,6 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id) goto err_no_mem; } - pm_suspend_ignore_children(&adev->dev, true); - dev->clk = devm_clk_get(&adev->dev, NULL); if (IS_ERR(dev->clk)) { dev_err(&adev->dev, "could not get i2c clock\n"); diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index 45ae3c025bf6..88444ef74943 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -21,7 +21,7 @@ #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/wait.h> -#include <linux/i2c-ocores.h> +#include <linux/platform_data/i2c-ocores.h> #include <linux/slab.h> #include <linux/io.h> #include <linux/log2.h> @@ -222,10 +222,7 @@ static int ocores_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) i2c->nmsgs = num; i2c->state = STATE_START; - oc_setreg(i2c, OCI2C_DATA, - (i2c->msg->addr << 1) | - ((i2c->msg->flags & I2C_M_RD) ? 1:0)); - + oc_setreg(i2c, OCI2C_DATA, i2c_8bit_addr_from_msg(i2c->msg)); oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START); if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) || diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index b9172f08fd05..65d06a819307 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -36,7 +36,7 @@ #include <linux/of.h> #include <linux/of_device.h> #include <linux/slab.h> -#include <linux/i2c-omap.h> +#include <linux/platform_data/i2c-omap.h> #include <linux/pm_runtime.h> #include <linux/pinctrl/consumer.h> diff --git a/drivers/i2c/busses/i2c-opal.c b/drivers/i2c/busses/i2c-opal.c index 0aabb7eca0c5..dc2a23f4fb52 100644 --- a/drivers/i2c/busses/i2c-opal.c +++ b/drivers/i2c/busses/i2c-opal.c @@ -94,8 +94,6 @@ static int i2c_opal_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, */ memset(&req, 0, sizeof(req)); switch(num) { - case 0: - return 0; case 1: req.type = (msgs[0].flags & I2C_M_RD) ? OPAL_I2C_RAW_READ : OPAL_I2C_RAW_WRITE; @@ -114,8 +112,6 @@ static int i2c_opal_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, req.size = cpu_to_be32(msgs[1].len); req.buffer_ra = cpu_to_be64(__pa(msgs[1].buf)); break; - default: - return -EOPNOTSUPP; } rc = i2c_opal_send_request(opal_id, &req); diff --git a/drivers/i2c/busses/i2c-pasemi.c b/drivers/i2c/busses/i2c-pasemi.c index df1dbc92a024..55fd5c6f3cca 100644 --- a/drivers/i2c/busses/i2c-pasemi.c +++ b/drivers/i2c/busses/i2c-pasemi.c @@ -121,7 +121,7 @@ static int pasemi_i2c_xfer_msg(struct i2c_adapter *adapter, read = msg->flags & I2C_M_RD ? 1 : 0; - TXFIFO_WR(smbus, MTXFIFO_START | (msg->addr << 1) | read); + TXFIFO_WR(smbus, MTXFIFO_START | i2c_8bit_addr_from_msg(msg)); if (read) { TXFIFO_WR(smbus, msg->len | MTXFIFO_READ | diff --git a/drivers/i2c/busses/i2c-pca-platform.c b/drivers/i2c/busses/i2c-pca-platform.c index bc2707ffd409..de3fe6e828cb 100644 --- a/drivers/i2c/busses/i2c-pca-platform.c +++ b/drivers/i2c/busses/i2c-pca-platform.c @@ -20,7 +20,7 @@ #include <linux/interrupt.h> #include <linux/platform_device.h> #include <linux/i2c-algo-pca.h> -#include <linux/i2c-pca-platform.h> +#include <linux/platform_data/i2c-pca-platform.h> #include <linux/gpio.h> #include <linux/gpio/consumer.h> #include <linux/io.h> diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index a542041df0cd..6e0e546ef83f 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -18,7 +18,6 @@ #include <linux/timer.h> #include <linux/completion.h> #include <linux/platform_device.h> -#include <linux/i2c-pnx.h> #include <linux/io.h> #include <linux/err.h> #include <linux/clk.h> @@ -29,6 +28,26 @@ #define I2C_PNX_SPEED_KHZ_DEFAULT 100 #define I2C_PNX_REGION_SIZE 0x100 +struct i2c_pnx_mif { + int ret; /* Return value */ + int mode; /* Interface mode */ + struct completion complete; /* I/O completion */ + struct timer_list timer; /* Timeout */ + u8 * buf; /* Data buffer */ + int len; /* Length of data buffer */ + int order; /* RX Bytes to order via TX */ +}; + +struct i2c_pnx_algo_data { + void __iomem *ioaddr; + struct i2c_pnx_mif mif; + int last; + struct clk *clk; + struct i2c_adapter adapter; + int irq; + u32 timeout; +}; + enum { mstatus_tdi = 0x00000001, mstatus_afi = 0x00000002, diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 904dfec7ab96..c86c3ae1318f 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -136,8 +136,13 @@ */ #define TOUT_MIN 2 +/* I2C Frequency Modes */ +#define I2C_STANDARD_FREQ 100000 +#define I2C_FAST_MODE_FREQ 400000 +#define I2C_FAST_MODE_PLUS_FREQ 1000000 + /* Default values. Use these if FW query fails */ -#define DEFAULT_CLK_FREQ 100000 +#define DEFAULT_CLK_FREQ I2C_STANDARD_FREQ #define DEFAULT_SRC_CLK 20000000 /* @@ -150,6 +155,10 @@ /* TAG length for DATA READ in RX FIFO */ #define READ_RX_TAGS_LEN 2 +static unsigned int scl_freq; +module_param_named(scl_freq, scl_freq, uint, 0444); +MODULE_PARM_DESC(scl_freq, "SCL frequency override"); + /* * count: no of blocks * pos: current block number @@ -453,7 +462,7 @@ static void qup_i2c_write_tx_fifo_v1(struct qup_i2c_dev *qup) { struct qup_i2c_block *blk = &qup->blk; struct i2c_msg *msg = qup->msg; - u32 addr = msg->addr << 1; + u32 addr = i2c_8bit_addr_from_msg(msg); u32 qup_tag; int idx; u32 val; @@ -1648,6 +1657,12 @@ static void qup_i2c_disable_clocks(struct qup_i2c_dev *qup) clk_disable_unprepare(qup->pclk); } +static const struct acpi_device_id qup_i2c_acpi_match[] = { + { "QCOM8010"}, + { }, +}; +MODULE_DEVICE_TABLE(acpi, qup_i2c_acpi_match); + static int qup_i2c_probe(struct platform_device *pdev) { static const int blk_sizes[] = {4, 16, 32}; @@ -1669,10 +1684,15 @@ static int qup_i2c_probe(struct platform_device *pdev) init_completion(&qup->xfer); platform_set_drvdata(pdev, qup); - ret = device_property_read_u32(qup->dev, "clock-frequency", &clk_freq); - if (ret) { - dev_notice(qup->dev, "using default clock-frequency %d", - DEFAULT_CLK_FREQ); + if (scl_freq) { + dev_notice(qup->dev, "Using override frequency of %u\n", scl_freq); + clk_freq = scl_freq; + } else { + ret = device_property_read_u32(qup->dev, "clock-frequency", &clk_freq); + if (ret) { + dev_notice(qup->dev, "using default clock-frequency %d", + DEFAULT_CLK_FREQ); + } } if (of_device_is_compatible(pdev->dev.of_node, "qcom,i2c-qup-v1.1.1")) { @@ -1682,7 +1702,10 @@ static int qup_i2c_probe(struct platform_device *pdev) } else { qup->adap.algo = &qup_i2c_algo_v2; is_qup_v1 = false; - ret = qup_i2c_req_dma(qup); + if (acpi_match_device(qup_i2c_acpi_match, qup->dev)) + goto nodma; + else + ret = qup_i2c_req_dma(qup); if (ret == -EPROBE_DEFER) goto fail_dma; @@ -1691,8 +1714,8 @@ static int qup_i2c_probe(struct platform_device *pdev) qup->max_xfer_sg_len = (MX_BLOCKS << 1); blocks = (MX_DMA_BLOCKS << 1) + 1; - qup->btx.sg = devm_kzalloc(&pdev->dev, - sizeof(*qup->btx.sg) * blocks, + qup->btx.sg = devm_kcalloc(&pdev->dev, + blocks, sizeof(*qup->btx.sg), GFP_KERNEL); if (!qup->btx.sg) { ret = -ENOMEM; @@ -1700,8 +1723,8 @@ static int qup_i2c_probe(struct platform_device *pdev) } sg_init_table(qup->btx.sg, blocks); - qup->brx.sg = devm_kzalloc(&pdev->dev, - sizeof(*qup->brx.sg) * blocks, + qup->brx.sg = devm_kcalloc(&pdev->dev, + blocks, sizeof(*qup->brx.sg), GFP_KERNEL); if (!qup->brx.sg) { ret = -ENOMEM; @@ -1734,8 +1757,8 @@ static int qup_i2c_probe(struct platform_device *pdev) } nodma: - /* We support frequencies up to FAST Mode (400KHz) */ - if (!clk_freq || clk_freq > 400000) { + /* We support frequencies up to FAST Mode Plus (1MHz) */ + if (!clk_freq || clk_freq > I2C_FAST_MODE_PLUS_FREQ) { dev_err(qup->dev, "clock frequency not supported %d\n", clk_freq); return -EINVAL; @@ -1839,9 +1862,15 @@ nodma: size = QUP_INPUT_FIFO_SIZE(io_mode); qup->in_fifo_sz = qup->in_blk_sz * (2 << size); - fs_div = ((src_clk_freq / clk_freq) / 2) - 3; hs_div = 3; - qup->clk_ctl = (hs_div << 8) | (fs_div & 0xff); + if (clk_freq <= I2C_STANDARD_FREQ) { + fs_div = ((src_clk_freq / clk_freq) / 2) - 3; + qup->clk_ctl = (hs_div << 8) | (fs_div & 0xff); + } else { + /* 33%/66% duty cycle */ + fs_div = ((src_clk_freq / clk_freq) - 6) * 2 / 3; + qup->clk_ctl = ((fs_div / 2) << 16) | (hs_div << 8) | (fs_div & 0xff); + } /* * Time it takes for a byte to be clocked out on the bus. @@ -1959,14 +1988,6 @@ static const struct of_device_id qup_i2c_dt_match[] = { }; MODULE_DEVICE_TABLE(of, qup_i2c_dt_match); -#if IS_ENABLED(CONFIG_ACPI) -static const struct acpi_device_id qup_i2c_acpi_match[] = { - { "QCOM8010"}, - { }, -}; -MODULE_DEVICE_TABLE(acpi, qup_i2c_acpi_match); -#endif - static struct platform_driver qup_i2c_driver = { .probe = qup_i2c_probe, .remove = qup_i2c_remove, diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index c6915b835396..5e310efd9446 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -329,7 +329,7 @@ static void rcar_i2c_prepare_msg(struct rcar_i2c_priv *priv) if (priv->msgs_left == 1) priv->flags |= ID_LAST_MSG; - rcar_i2c_write(priv, ICMAR, (priv->msg->addr << 1) | read); + rcar_i2c_write(priv, ICMAR, i2c_8bit_addr_from_msg(priv->msg)); /* * We don't have a test case but the HW engineers say that the write order * of ICMSR and ICMCR depends on whether we issue START or REP_START. Since @@ -542,6 +542,8 @@ static void rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr) * If next received data is the _LAST_, go to STOP phase. Might be * overwritten by REP START when setting up a new msg. Not elegant * but the only stable sequence for REP START I have found so far. + * If you want to change this code, make sure sending one transfer with + * four messages (WR-RD-WR-RD) works! */ if (priv->pos + 1 >= msg->len) rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP); diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c index 95c2f1ce3cad..5f1fca7880b1 100644 --- a/drivers/i2c/busses/i2c-riic.c +++ b/drivers/i2c/busses/i2c-riic.c @@ -167,15 +167,14 @@ static irqreturn_t riic_tdre_isr(int irq, void *data) return IRQ_NONE; if (riic->bytes_left == RIIC_INIT_MSG) { - val = !!(riic->msg->flags & I2C_M_RD); - if (val) + if (riic->msg->flags & I2C_M_RD) /* On read, switch over to receive interrupt */ riic_clear_set_bit(riic, ICIER_TIE, ICIER_RIE, RIIC_ICIER); else /* On write, initialize length */ riic->bytes_left = riic->msg->len; - val |= (riic->msg->addr << 1); + val = i2c_8bit_addr_from_msg(riic->msg); } else { val = *riic->buf; riic->buf++; diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c index e1a18d989f83..b8a2728dd4b6 100644 --- a/drivers/i2c/busses/i2c-rk3x.c +++ b/drivers/i2c/busses/i2c-rk3x.c @@ -1326,8 +1326,6 @@ static int rk3x_i2c_probe(struct platform_device *pdev) if (ret < 0) goto err_clk_notifier; - dev_info(&pdev->dev, "Initialized RK3xxx I2C bus at %p\n", i2c->regs); - return 0; err_clk_notifier: diff --git a/drivers/i2c/busses/i2c-robotfuzz-osif.c b/drivers/i2c/busses/i2c-robotfuzz-osif.c index 9c0f52b7ff7e..d848cf515234 100644 --- a/drivers/i2c/busses/i2c-robotfuzz-osif.c +++ b/drivers/i2c/busses/i2c-robotfuzz-osif.c @@ -62,27 +62,24 @@ static int osif_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, { struct osif_priv *priv = adapter->algo_data; struct i2c_msg *pmsg; - int ret = 0; - int i, cmd; + int ret; + int i; - for (i = 0; ret >= 0 && i < num; i++) { + for (i = 0; i < num; i++) { pmsg = &msgs[i]; if (pmsg->flags & I2C_M_RD) { - cmd = OSIFI2C_READ; - - ret = osif_usb_read(adapter, cmd, pmsg->flags, - pmsg->addr, pmsg->buf, - pmsg->len); + ret = osif_usb_read(adapter, OSIFI2C_READ, + pmsg->flags, pmsg->addr, + pmsg->buf, pmsg->len); if (ret != pmsg->len) { dev_err(&adapter->dev, "failure reading data\n"); return -EREMOTEIO; } } else { - cmd = OSIFI2C_WRITE; - - ret = osif_usb_write(adapter, cmd, pmsg->flags, - pmsg->addr, pmsg->buf, pmsg->len); + ret = osif_usb_write(adapter, OSIFI2C_WRITE, + pmsg->flags, pmsg->addr, + pmsg->buf, pmsg->len); if (ret != pmsg->len) { dev_err(&adapter->dev, "failure writing data\n"); return -EREMOTEIO; diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 5d97510ee48b..9fe2b6951895 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -154,8 +154,6 @@ static const struct of_device_id s3c24xx_i2c_match[] = { { .compatible = "samsung,s3c2440-i2c", .data = (void *)QUIRK_S3C2440 }, { .compatible = "samsung,s3c2440-hdmiphy-i2c", .data = (void *)(QUIRK_S3C2440 | QUIRK_HDMIPHY | QUIRK_NO_GPIO) }, - { .compatible = "samsung,exynos5440-i2c", - .data = (void *)(QUIRK_S3C2440 | QUIRK_NO_GPIO) }, { .compatible = "samsung,exynos5-sata-phy-i2c", .data = (void *)(QUIRK_S3C2440 | QUIRK_POLL | QUIRK_NO_GPIO) }, {}, diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index d856bc211715..5fda4188a9e5 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -899,17 +899,6 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) if (resource_size(res) > 0x17) pd->flags |= IIC_FLAG_HAS_ICIC67; - /* Enable Runtime PM for this device. - * - * Also tell the Runtime PM core to ignore children - * for this device since it is valid for us to suspend - * this I2C master driver even though the slave devices - * on the I2C bus may not be suspended. - * - * The state of the I2C hardware bus is unaffected by - * the Runtime PM state. - */ - pm_suspend_ignore_children(&dev->dev, true); pm_runtime_enable(&dev->dev); pm_runtime_get_sync(&dev->dev); diff --git a/drivers/i2c/busses/i2c-stm32.c b/drivers/i2c/busses/i2c-stm32.c new file mode 100644 index 000000000000..d75fbcbf02ef --- /dev/null +++ b/drivers/i2c/busses/i2c-stm32.c @@ -0,0 +1,153 @@ +/* + * i2c-stm32.c + * + * Copyright (C) M'boumba Cedric Madianga 2017 + * Author: M'boumba Cedric Madianga <cedric.madianga@gmail.com> + * + * License terms: GNU General Public License (GPL), version 2 + */ + +#include "i2c-stm32.h" + +/* Functions for DMA support */ +struct stm32_i2c_dma *stm32_i2c_dma_request(struct device *dev, + dma_addr_t phy_addr, + u32 txdr_offset, + u32 rxdr_offset) +{ + struct stm32_i2c_dma *dma; + struct dma_slave_config dma_sconfig; + int ret; + + dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL); + if (!dma) + return NULL; + + /* Request and configure I2C TX dma channel */ + dma->chan_tx = dma_request_slave_channel(dev, "tx"); + if (!dma->chan_tx) { + dev_dbg(dev, "can't request DMA tx channel\n"); + ret = -EINVAL; + goto fail_al; + } + + memset(&dma_sconfig, 0, sizeof(dma_sconfig)); + dma_sconfig.dst_addr = phy_addr + txdr_offset; + dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + dma_sconfig.dst_maxburst = 1; + dma_sconfig.direction = DMA_MEM_TO_DEV; + ret = dmaengine_slave_config(dma->chan_tx, &dma_sconfig); + if (ret < 0) { + dev_err(dev, "can't configure tx channel\n"); + goto fail_tx; + } + + /* Request and configure I2C RX dma channel */ + dma->chan_rx = dma_request_slave_channel(dev, "rx"); + if (!dma->chan_rx) { + dev_err(dev, "can't request DMA rx channel\n"); + ret = -EINVAL; + goto fail_tx; + } + + memset(&dma_sconfig, 0, sizeof(dma_sconfig)); + dma_sconfig.src_addr = phy_addr + rxdr_offset; + dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + dma_sconfig.src_maxburst = 1; + dma_sconfig.direction = DMA_DEV_TO_MEM; + ret = dmaengine_slave_config(dma->chan_rx, &dma_sconfig); + if (ret < 0) { + dev_err(dev, "can't configure rx channel\n"); + goto fail_rx; + } + + init_completion(&dma->dma_complete); + + dev_info(dev, "using %s (tx) and %s (rx) for DMA transfers\n", + dma_chan_name(dma->chan_tx), dma_chan_name(dma->chan_rx)); + + return dma; + +fail_rx: + dma_release_channel(dma->chan_rx); +fail_tx: + dma_release_channel(dma->chan_tx); +fail_al: + devm_kfree(dev, dma); + dev_info(dev, "can't use DMA\n"); + + return NULL; +} + +void stm32_i2c_dma_free(struct stm32_i2c_dma *dma) +{ + dma->dma_buf = 0; + dma->dma_len = 0; + + dma_release_channel(dma->chan_tx); + dma->chan_tx = NULL; + + dma_release_channel(dma->chan_rx); + dma->chan_rx = NULL; + + dma->chan_using = NULL; +} + +int stm32_i2c_prep_dma_xfer(struct device *dev, struct stm32_i2c_dma *dma, + bool rd_wr, u32 len, u8 *buf, + dma_async_tx_callback callback, + void *dma_async_param) +{ + struct dma_async_tx_descriptor *txdesc; + struct device *chan_dev; + int ret; + + if (rd_wr) { + dma->chan_using = dma->chan_rx; + dma->dma_transfer_dir = DMA_DEV_TO_MEM; + dma->dma_data_dir = DMA_FROM_DEVICE; + } else { + dma->chan_using = dma->chan_tx; + dma->dma_transfer_dir = DMA_MEM_TO_DEV; + dma->dma_data_dir = DMA_TO_DEVICE; + } + + dma->dma_len = len; + chan_dev = dma->chan_using->device->dev; + + dma->dma_buf = dma_map_single(chan_dev, buf, dma->dma_len, + dma->dma_data_dir); + if (dma_mapping_error(chan_dev, dma->dma_buf)) { + dev_err(dev, "DMA mapping failed\n"); + return -EINVAL; + } + + txdesc = dmaengine_prep_slave_single(dma->chan_using, dma->dma_buf, + dma->dma_len, + dma->dma_transfer_dir, + DMA_PREP_INTERRUPT); + if (!txdesc) { + dev_err(dev, "Not able to get desc for DMA xfer\n"); + ret = -EINVAL; + goto err; + } + + reinit_completion(&dma->dma_complete); + + txdesc->callback = callback; + txdesc->callback_param = dma_async_param; + ret = dma_submit_error(dmaengine_submit(txdesc)); + if (ret < 0) { + dev_err(dev, "DMA submit failed\n"); + goto err; + } + + dma_async_issue_pending(dma->chan_using); + + return 0; + +err: + dma_unmap_single(chan_dev, dma->dma_buf, dma->dma_len, + dma->dma_data_dir); + return ret; +} diff --git a/drivers/i2c/busses/i2c-stm32.h b/drivers/i2c/busses/i2c-stm32.h index d4f9cef251ac..868755f82f88 100644 --- a/drivers/i2c/busses/i2c-stm32.h +++ b/drivers/i2c/busses/i2c-stm32.h @@ -11,6 +11,10 @@ #ifndef _I2C_STM32_H #define _I2C_STM32_H +#include <linux/dma-direction.h> +#include <linux/dmaengine.h> +#include <linux/dma-mapping.h> + enum stm32_i2c_speed { STM32_I2C_SPEED_STANDARD, /* 100 kHz */ STM32_I2C_SPEED_FAST, /* 400 kHz */ @@ -18,4 +22,37 @@ enum stm32_i2c_speed { STM32_I2C_SPEED_END, }; +/** + * struct stm32_i2c_dma - DMA specific data + * @chan_tx: dma channel for TX transfer + * @chan_rx: dma channel for RX transfer + * @chan_using: dma channel used for the current transfer (TX or RX) + * @dma_buf: dma buffer + * @dma_len: dma buffer len + * @dma_transfer_dir: dma transfer direction indicator + * @dma_data_dir: dma transfer mode indicator + * @dma_complete: dma transfer completion + */ +struct stm32_i2c_dma { + struct dma_chan *chan_tx; + struct dma_chan *chan_rx; + struct dma_chan *chan_using; + dma_addr_t dma_buf; + unsigned int dma_len; + enum dma_transfer_direction dma_transfer_dir; + enum dma_data_direction dma_data_dir; + struct completion dma_complete; +}; + +struct stm32_i2c_dma *stm32_i2c_dma_request(struct device *dev, + dma_addr_t phy_addr, + u32 txdr_offset, u32 rxdr_offset); + +void stm32_i2c_dma_free(struct stm32_i2c_dma *dma); + +int stm32_i2c_prep_dma_xfer(struct device *dev, struct stm32_i2c_dma *dma, + bool rd_wr, u32 len, u8 *buf, + dma_async_tx_callback callback, + void *dma_async_param); + #endif /* _I2C_STM32_H */ diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c index f273e28c39db..62d023e737d9 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c @@ -35,6 +35,9 @@ /* STM32F7 I2C registers */ #define STM32F7_I2C_CR1 0x00 #define STM32F7_I2C_CR2 0x04 +#define STM32F7_I2C_OAR1 0x08 +#define STM32F7_I2C_OAR2 0x0C +#define STM32F7_I2C_PECR 0x20 #define STM32F7_I2C_TIMINGR 0x10 #define STM32F7_I2C_ISR 0x18 #define STM32F7_I2C_ICR 0x1C @@ -42,6 +45,10 @@ #define STM32F7_I2C_TXDR 0x28 /* STM32F7 I2C control 1 */ +#define STM32F7_I2C_CR1_PECEN BIT(23) +#define STM32F7_I2C_CR1_SBC BIT(16) +#define STM32F7_I2C_CR1_RXDMAEN BIT(15) +#define STM32F7_I2C_CR1_TXDMAEN BIT(14) #define STM32F7_I2C_CR1_ANFOFF BIT(12) #define STM32F7_I2C_CR1_ERRIE BIT(7) #define STM32F7_I2C_CR1_TCIE BIT(6) @@ -57,34 +64,77 @@ | STM32F7_I2C_CR1_NACKIE \ | STM32F7_I2C_CR1_RXIE \ | STM32F7_I2C_CR1_TXIE) +#define STM32F7_I2C_XFER_IRQ_MASK (STM32F7_I2C_CR1_TCIE \ + | STM32F7_I2C_CR1_STOPIE \ + | STM32F7_I2C_CR1_NACKIE \ + | STM32F7_I2C_CR1_RXIE \ + | STM32F7_I2C_CR1_TXIE) /* STM32F7 I2C control 2 */ +#define STM32F7_I2C_CR2_PECBYTE BIT(26) #define STM32F7_I2C_CR2_RELOAD BIT(24) #define STM32F7_I2C_CR2_NBYTES_MASK GENMASK(23, 16) #define STM32F7_I2C_CR2_NBYTES(n) (((n) & 0xff) << 16) #define STM32F7_I2C_CR2_NACK BIT(15) #define STM32F7_I2C_CR2_STOP BIT(14) #define STM32F7_I2C_CR2_START BIT(13) +#define STM32F7_I2C_CR2_HEAD10R BIT(12) +#define STM32F7_I2C_CR2_ADD10 BIT(11) #define STM32F7_I2C_CR2_RD_WRN BIT(10) +#define STM32F7_I2C_CR2_SADD10_MASK GENMASK(9, 0) +#define STM32F7_I2C_CR2_SADD10(n) (((n) & \ + STM32F7_I2C_CR2_SADD10_MASK)) #define STM32F7_I2C_CR2_SADD7_MASK GENMASK(7, 1) #define STM32F7_I2C_CR2_SADD7(n) (((n) & 0x7f) << 1) +/* STM32F7 I2C Own Address 1 */ +#define STM32F7_I2C_OAR1_OA1EN BIT(15) +#define STM32F7_I2C_OAR1_OA1MODE BIT(10) +#define STM32F7_I2C_OAR1_OA1_10_MASK GENMASK(9, 0) +#define STM32F7_I2C_OAR1_OA1_10(n) (((n) & \ + STM32F7_I2C_OAR1_OA1_10_MASK)) +#define STM32F7_I2C_OAR1_OA1_7_MASK GENMASK(7, 1) +#define STM32F7_I2C_OAR1_OA1_7(n) (((n) & 0x7f) << 1) +#define STM32F7_I2C_OAR1_MASK (STM32F7_I2C_OAR1_OA1_7_MASK \ + | STM32F7_I2C_OAR1_OA1_10_MASK \ + | STM32F7_I2C_OAR1_OA1EN \ + | STM32F7_I2C_OAR1_OA1MODE) + +/* STM32F7 I2C Own Address 2 */ +#define STM32F7_I2C_OAR2_OA2EN BIT(15) +#define STM32F7_I2C_OAR2_OA2MSK_MASK GENMASK(10, 8) +#define STM32F7_I2C_OAR2_OA2MSK(n) (((n) & 0x7) << 8) +#define STM32F7_I2C_OAR2_OA2_7_MASK GENMASK(7, 1) +#define STM32F7_I2C_OAR2_OA2_7(n) (((n) & 0x7f) << 1) +#define STM32F7_I2C_OAR2_MASK (STM32F7_I2C_OAR2_OA2MSK_MASK \ + | STM32F7_I2C_OAR2_OA2_7_MASK \ + | STM32F7_I2C_OAR2_OA2EN) + /* STM32F7 I2C Interrupt Status */ +#define STM32F7_I2C_ISR_ADDCODE_MASK GENMASK(23, 17) +#define STM32F7_I2C_ISR_ADDCODE_GET(n) \ + (((n) & STM32F7_I2C_ISR_ADDCODE_MASK) >> 17) +#define STM32F7_I2C_ISR_DIR BIT(16) #define STM32F7_I2C_ISR_BUSY BIT(15) +#define STM32F7_I2C_ISR_PECERR BIT(11) #define STM32F7_I2C_ISR_ARLO BIT(9) #define STM32F7_I2C_ISR_BERR BIT(8) #define STM32F7_I2C_ISR_TCR BIT(7) #define STM32F7_I2C_ISR_TC BIT(6) #define STM32F7_I2C_ISR_STOPF BIT(5) #define STM32F7_I2C_ISR_NACKF BIT(4) +#define STM32F7_I2C_ISR_ADDR BIT(3) #define STM32F7_I2C_ISR_RXNE BIT(2) #define STM32F7_I2C_ISR_TXIS BIT(1) +#define STM32F7_I2C_ISR_TXE BIT(0) /* STM32F7 I2C Interrupt Clear */ +#define STM32F7_I2C_ICR_PECCF BIT(11) #define STM32F7_I2C_ICR_ARLOCF BIT(9) #define STM32F7_I2C_ICR_BERRCF BIT(8) #define STM32F7_I2C_ICR_STOPCF BIT(5) #define STM32F7_I2C_ICR_NACKCF BIT(4) +#define STM32F7_I2C_ICR_ADDRCF BIT(3) /* STM32F7 I2C Timing */ #define STM32F7_I2C_TIMINGR_PRESC(n) (((n) & 0xf) << 28) @@ -94,6 +144,8 @@ #define STM32F7_I2C_TIMINGR_SCLL(n) ((n) & 0xff) #define STM32F7_I2C_MAX_LEN 0xff +#define STM32F7_I2C_DMA_LEN_MIN 0x16 +#define STM32F7_I2C_MAX_SLAVE 0x2 #define STM32F7_I2C_DNF_DEFAULT 0 #define STM32F7_I2C_DNF_MAX 16 @@ -159,11 +211,12 @@ struct stm32f7_i2c_setup { /** * struct stm32f7_i2c_timings - private I2C output parameters - * @prec: Prescaler value + * @node: List entry + * @presc: Prescaler value * @scldel: Data setup time * @sdadel: Data hold time * @sclh: SCL high period (master mode) - * @sclh: SCL low period (master mode) + * @scll: SCL low period (master mode) */ struct stm32f7_i2c_timings { struct list_head node; @@ -176,18 +229,30 @@ struct stm32f7_i2c_timings { /** * struct stm32f7_i2c_msg - client specific data - * @addr: 8-bit slave addr, including r/w bit + * @addr: 8-bit or 10-bit slave addr, including r/w bit * @count: number of bytes to be transferred * @buf: data buffer * @result: result of the transfer * @stop: last I2C msg to be sent, i.e. STOP to be generated + * @smbus: boolean to know if the I2C IP is used in SMBus mode + * @size: type of SMBus protocol + * @read_write: direction of SMBus protocol + * SMBus block read and SMBus block write - block read process call protocols + * @smbus_buf: buffer to be used for SMBus protocol transfer. It will + * contain a maximum of 32 bytes of data + byte command + byte count + PEC + * This buffer has to be 32-bit aligned to be compliant with memory address + * register in DMA mode. */ struct stm32f7_i2c_msg { - u8 addr; + u16 addr; u32 count; u8 *buf; int result; bool stop; + bool smbus; + int size; + char read_write; + u8 smbus_buf[I2C_SMBUS_BLOCK_MAX + 3] __aligned(4); }; /** @@ -204,6 +269,13 @@ struct stm32f7_i2c_msg { * @f7_msg: customized i2c msg for driver usage * @setup: I2C timing input setup * @timing: I2C computed timings + * @slave: list of slave devices registered on the I2C bus + * @slave_running: slave device currently used + * @slave_dir: transfer direction for the current slave device + * @master_mode: boolean to know in which mode the I2C is running (master or + * slave) + * @dma: dma data + * @use_dma: boolean to know if dma is used in the current transfer */ struct stm32f7_i2c_dev { struct i2c_adapter adap; @@ -218,6 +290,12 @@ struct stm32f7_i2c_dev { struct stm32f7_i2c_msg f7_msg; struct stm32f7_i2c_setup setup; struct stm32f7_i2c_timings timing; + struct i2c_client *slave[STM32F7_I2C_MAX_SLAVE]; + struct i2c_client *slave_running; + u32 slave_dir; + bool master_mode; + struct stm32_i2c_dma *dma; + bool use_dma; }; /** @@ -283,6 +361,11 @@ static inline void stm32f7_i2c_clr_bits(void __iomem *reg, u32 mask) writel_relaxed(readl_relaxed(reg) & ~mask, reg); } +static void stm32f7_i2c_disable_irq(struct stm32f7_i2c_dev *i2c_dev, u32 mask) +{ + stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1, mask); +} + static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, struct stm32f7_i2c_setup *setup, struct stm32f7_i2c_timings *output) @@ -524,6 +607,25 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev, return 0; } +static void stm32f7_i2c_disable_dma_req(struct stm32f7_i2c_dev *i2c_dev) +{ + void __iomem *base = i2c_dev->base; + u32 mask = STM32F7_I2C_CR1_RXDMAEN | STM32F7_I2C_CR1_TXDMAEN; + + stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR1, mask); +} + +static void stm32f7_i2c_dma_callback(void *arg) +{ + struct stm32f7_i2c_dev *i2c_dev = (struct stm32f7_i2c_dev *)arg; + struct stm32_i2c_dma *dma = i2c_dev->dma; + struct device *dev = dma->chan_using->device->dev; + + stm32f7_i2c_disable_dma_req(i2c_dev); + dma_unmap_single(dev, dma->dma_buf, dma->dma_len, dma->dma_data_dir); + complete(&dma->dma_complete); +} + static void stm32f7_i2c_hw_config(struct stm32f7_i2c_dev *i2c_dev) { struct stm32f7_i2c_timings *t = &i2c_dev->timing; @@ -567,6 +669,9 @@ static void stm32f7_i2c_read_rx_data(struct stm32f7_i2c_dev *i2c_dev) if (f7_msg->count) { *f7_msg->buf++ = readb_relaxed(base + STM32F7_I2C_RXDR); f7_msg->count--; + } else { + /* Flush RX buffer has no data is expected */ + readb_relaxed(base + STM32F7_I2C_RXDR); } } @@ -575,6 +680,9 @@ static void stm32f7_i2c_reload(struct stm32f7_i2c_dev *i2c_dev) struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; u32 cr2; + if (i2c_dev->use_dma) + f7_msg->count -= STM32F7_I2C_MAX_LEN; + cr2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR2); cr2 &= ~STM32F7_I2C_CR2_NBYTES_MASK; @@ -588,6 +696,43 @@ static void stm32f7_i2c_reload(struct stm32f7_i2c_dev *i2c_dev) writel_relaxed(cr2, i2c_dev->base + STM32F7_I2C_CR2); } +static void stm32f7_i2c_smbus_reload(struct stm32f7_i2c_dev *i2c_dev) +{ + struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; + u32 cr2; + u8 *val; + + /* + * For I2C_SMBUS_BLOCK_DATA && I2C_SMBUS_BLOCK_PROC_CALL, the first + * data received inform us how many data will follow. + */ + stm32f7_i2c_read_rx_data(i2c_dev); + + /* + * Update NBYTES with the value read to continue the transfer + */ + val = f7_msg->buf - sizeof(u8); + f7_msg->count = *val; + cr2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR2); + cr2 &= ~(STM32F7_I2C_CR2_NBYTES_MASK | STM32F7_I2C_CR2_RELOAD); + cr2 |= STM32F7_I2C_CR2_NBYTES(f7_msg->count); + writel_relaxed(cr2, i2c_dev->base + STM32F7_I2C_CR2); +} + +static int stm32f7_i2c_release_bus(struct i2c_adapter *i2c_adap) +{ + struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(i2c_adap); + + dev_info(i2c_dev->dev, "Trying to recover bus\n"); + + stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1, + STM32F7_I2C_CR1_PE); + + stm32f7_i2c_hw_config(i2c_dev); + + return 0; +} + static int stm32f7_i2c_wait_free_bus(struct stm32f7_i2c_dev *i2c_dev) { u32 status; @@ -597,12 +742,18 @@ static int stm32f7_i2c_wait_free_bus(struct stm32f7_i2c_dev *i2c_dev) status, !(status & STM32F7_I2C_ISR_BUSY), 10, 1000); + if (!ret) + return 0; + + dev_info(i2c_dev->dev, "bus busy\n"); + + ret = stm32f7_i2c_release_bus(&i2c_dev->adap); if (ret) { - dev_dbg(i2c_dev->dev, "bus busy\n"); - ret = -EBUSY; + dev_err(i2c_dev->dev, "Failed to recover the bus (%d)\n", ret); + return ret; } - return ret; + return -EBUSY; } static void stm32f7_i2c_xfer_msg(struct stm32f7_i2c_dev *i2c_dev, @@ -611,6 +762,7 @@ static void stm32f7_i2c_xfer_msg(struct stm32f7_i2c_dev *i2c_dev, struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; void __iomem *base = i2c_dev->base; u32 cr1, cr2; + int ret; f7_msg->addr = msg->addr; f7_msg->buf = msg->buf; @@ -629,8 +781,15 @@ static void stm32f7_i2c_xfer_msg(struct stm32f7_i2c_dev *i2c_dev, cr2 |= STM32F7_I2C_CR2_RD_WRN; /* Set slave address */ - cr2 &= ~STM32F7_I2C_CR2_SADD7_MASK; - cr2 |= STM32F7_I2C_CR2_SADD7(f7_msg->addr); + cr2 &= ~(STM32F7_I2C_CR2_HEAD10R | STM32F7_I2C_CR2_ADD10); + if (msg->flags & I2C_M_TEN) { + cr2 &= ~STM32F7_I2C_CR2_SADD10_MASK; + cr2 |= STM32F7_I2C_CR2_SADD10(f7_msg->addr); + cr2 |= STM32F7_I2C_CR2_ADD10; + } else { + cr2 &= ~STM32F7_I2C_CR2_SADD7_MASK; + cr2 |= STM32F7_I2C_CR2_SADD7(f7_msg->addr); + } /* Set nb bytes to transfer and reload if needed */ cr2 &= ~(STM32F7_I2C_CR2_NBYTES_MASK | STM32F7_I2C_CR2_RELOAD); @@ -645,16 +804,286 @@ static void stm32f7_i2c_xfer_msg(struct stm32f7_i2c_dev *i2c_dev, cr1 |= STM32F7_I2C_CR1_ERRIE | STM32F7_I2C_CR1_TCIE | STM32F7_I2C_CR1_STOPIE | STM32F7_I2C_CR1_NACKIE; - /* Clear TX/RX interrupt */ + /* Clear DMA req and TX/RX interrupt */ + cr1 &= ~(STM32F7_I2C_CR1_RXIE | STM32F7_I2C_CR1_TXIE | + STM32F7_I2C_CR1_RXDMAEN | STM32F7_I2C_CR1_TXDMAEN); + + /* Configure DMA or enable RX/TX interrupt */ + i2c_dev->use_dma = false; + if (i2c_dev->dma && f7_msg->count >= STM32F7_I2C_DMA_LEN_MIN) { + ret = stm32_i2c_prep_dma_xfer(i2c_dev->dev, i2c_dev->dma, + msg->flags & I2C_M_RD, + f7_msg->count, f7_msg->buf, + stm32f7_i2c_dma_callback, + i2c_dev); + if (!ret) + i2c_dev->use_dma = true; + else + dev_warn(i2c_dev->dev, "can't use DMA\n"); + } + + if (!i2c_dev->use_dma) { + if (msg->flags & I2C_M_RD) + cr1 |= STM32F7_I2C_CR1_RXIE; + else + cr1 |= STM32F7_I2C_CR1_TXIE; + } else { + if (msg->flags & I2C_M_RD) + cr1 |= STM32F7_I2C_CR1_RXDMAEN; + else + cr1 |= STM32F7_I2C_CR1_TXDMAEN; + } + + /* Configure Start/Repeated Start */ + cr2 |= STM32F7_I2C_CR2_START; + + i2c_dev->master_mode = true; + + /* Write configurations registers */ + writel_relaxed(cr1, base + STM32F7_I2C_CR1); + writel_relaxed(cr2, base + STM32F7_I2C_CR2); +} + +static int stm32f7_i2c_smbus_xfer_msg(struct stm32f7_i2c_dev *i2c_dev, + unsigned short flags, u8 command, + union i2c_smbus_data *data) +{ + struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; + struct device *dev = i2c_dev->dev; + void __iomem *base = i2c_dev->base; + u32 cr1, cr2; + int i, ret; + + f7_msg->result = 0; + reinit_completion(&i2c_dev->complete); + + cr2 = readl_relaxed(base + STM32F7_I2C_CR2); + cr1 = readl_relaxed(base + STM32F7_I2C_CR1); + + /* Set transfer direction */ + cr2 &= ~STM32F7_I2C_CR2_RD_WRN; + if (f7_msg->read_write) + cr2 |= STM32F7_I2C_CR2_RD_WRN; + + /* Set slave address */ + cr2 &= ~(STM32F7_I2C_CR2_ADD10 | STM32F7_I2C_CR2_SADD7_MASK); + cr2 |= STM32F7_I2C_CR2_SADD7(f7_msg->addr); + + f7_msg->smbus_buf[0] = command; + switch (f7_msg->size) { + case I2C_SMBUS_QUICK: + f7_msg->stop = true; + f7_msg->count = 0; + break; + case I2C_SMBUS_BYTE: + f7_msg->stop = true; + f7_msg->count = 1; + break; + case I2C_SMBUS_BYTE_DATA: + if (f7_msg->read_write) { + f7_msg->stop = false; + f7_msg->count = 1; + cr2 &= ~STM32F7_I2C_CR2_RD_WRN; + } else { + f7_msg->stop = true; + f7_msg->count = 2; + f7_msg->smbus_buf[1] = data->byte; + } + break; + case I2C_SMBUS_WORD_DATA: + if (f7_msg->read_write) { + f7_msg->stop = false; + f7_msg->count = 1; + cr2 &= ~STM32F7_I2C_CR2_RD_WRN; + } else { + f7_msg->stop = true; + f7_msg->count = 3; + f7_msg->smbus_buf[1] = data->word & 0xff; + f7_msg->smbus_buf[2] = data->word >> 8; + } + break; + case I2C_SMBUS_BLOCK_DATA: + if (f7_msg->read_write) { + f7_msg->stop = false; + f7_msg->count = 1; + cr2 &= ~STM32F7_I2C_CR2_RD_WRN; + } else { + f7_msg->stop = true; + if (data->block[0] > I2C_SMBUS_BLOCK_MAX || + !data->block[0]) { + dev_err(dev, "Invalid block write size %d\n", + data->block[0]); + return -EINVAL; + } + f7_msg->count = data->block[0] + 2; + for (i = 1; i < f7_msg->count; i++) + f7_msg->smbus_buf[i] = data->block[i - 1]; + } + break; + case I2C_SMBUS_PROC_CALL: + f7_msg->stop = false; + f7_msg->count = 3; + f7_msg->smbus_buf[1] = data->word & 0xff; + f7_msg->smbus_buf[2] = data->word >> 8; + cr2 &= ~STM32F7_I2C_CR2_RD_WRN; + f7_msg->read_write = I2C_SMBUS_READ; + break; + case I2C_SMBUS_BLOCK_PROC_CALL: + f7_msg->stop = false; + if (data->block[0] > I2C_SMBUS_BLOCK_MAX - 1) { + dev_err(dev, "Invalid block write size %d\n", + data->block[0]); + return -EINVAL; + } + f7_msg->count = data->block[0] + 2; + for (i = 1; i < f7_msg->count; i++) + f7_msg->smbus_buf[i] = data->block[i - 1]; + cr2 &= ~STM32F7_I2C_CR2_RD_WRN; + f7_msg->read_write = I2C_SMBUS_READ; + break; + default: + dev_err(dev, "Unsupported smbus protocol %d\n", f7_msg->size); + return -EOPNOTSUPP; + } + + f7_msg->buf = f7_msg->smbus_buf; + + /* Configure PEC */ + if ((flags & I2C_CLIENT_PEC) && f7_msg->size != I2C_SMBUS_QUICK) { + cr1 |= STM32F7_I2C_CR1_PECEN; + cr2 |= STM32F7_I2C_CR2_PECBYTE; + if (!f7_msg->read_write) + f7_msg->count++; + } else { + cr1 &= ~STM32F7_I2C_CR1_PECEN; + cr2 &= ~STM32F7_I2C_CR2_PECBYTE; + } + + /* Set number of bytes to be transferred */ + cr2 &= ~(STM32F7_I2C_CR2_NBYTES_MASK | STM32F7_I2C_CR2_RELOAD); + cr2 |= STM32F7_I2C_CR2_NBYTES(f7_msg->count); + + /* Enable NACK, STOP, error and transfer complete interrupts */ + cr1 |= STM32F7_I2C_CR1_ERRIE | STM32F7_I2C_CR1_TCIE | + STM32F7_I2C_CR1_STOPIE | STM32F7_I2C_CR1_NACKIE; + + /* Clear DMA req and TX/RX interrupt */ + cr1 &= ~(STM32F7_I2C_CR1_RXIE | STM32F7_I2C_CR1_TXIE | + STM32F7_I2C_CR1_RXDMAEN | STM32F7_I2C_CR1_TXDMAEN); + + /* Configure DMA or enable RX/TX interrupt */ + i2c_dev->use_dma = false; + if (i2c_dev->dma && f7_msg->count >= STM32F7_I2C_DMA_LEN_MIN) { + ret = stm32_i2c_prep_dma_xfer(i2c_dev->dev, i2c_dev->dma, + cr2 & STM32F7_I2C_CR2_RD_WRN, + f7_msg->count, f7_msg->buf, + stm32f7_i2c_dma_callback, + i2c_dev); + if (!ret) + i2c_dev->use_dma = true; + else + dev_warn(i2c_dev->dev, "can't use DMA\n"); + } + + if (!i2c_dev->use_dma) { + if (cr2 & STM32F7_I2C_CR2_RD_WRN) + cr1 |= STM32F7_I2C_CR1_RXIE; + else + cr1 |= STM32F7_I2C_CR1_TXIE; + } else { + if (cr2 & STM32F7_I2C_CR2_RD_WRN) + cr1 |= STM32F7_I2C_CR1_RXDMAEN; + else + cr1 |= STM32F7_I2C_CR1_TXDMAEN; + } + + /* Set Start bit */ + cr2 |= STM32F7_I2C_CR2_START; + + i2c_dev->master_mode = true; + + /* Write configurations registers */ + writel_relaxed(cr1, base + STM32F7_I2C_CR1); + writel_relaxed(cr2, base + STM32F7_I2C_CR2); + + return 0; +} + +static void stm32f7_i2c_smbus_rep_start(struct stm32f7_i2c_dev *i2c_dev) +{ + struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; + void __iomem *base = i2c_dev->base; + u32 cr1, cr2; + int ret; + + cr2 = readl_relaxed(base + STM32F7_I2C_CR2); + cr1 = readl_relaxed(base + STM32F7_I2C_CR1); + + /* Set transfer direction */ + cr2 |= STM32F7_I2C_CR2_RD_WRN; + + switch (f7_msg->size) { + case I2C_SMBUS_BYTE_DATA: + f7_msg->count = 1; + break; + case I2C_SMBUS_WORD_DATA: + case I2C_SMBUS_PROC_CALL: + f7_msg->count = 2; + break; + case I2C_SMBUS_BLOCK_DATA: + case I2C_SMBUS_BLOCK_PROC_CALL: + f7_msg->count = 1; + cr2 |= STM32F7_I2C_CR2_RELOAD; + break; + } + + f7_msg->buf = f7_msg->smbus_buf; + f7_msg->stop = true; + + /* Add one byte for PEC if needed */ + if (cr1 & STM32F7_I2C_CR1_PECEN) + f7_msg->count++; + + /* Set number of bytes to be transferred */ + cr2 &= ~(STM32F7_I2C_CR2_NBYTES_MASK); + cr2 |= STM32F7_I2C_CR2_NBYTES(f7_msg->count); + + /* + * Configure RX/TX interrupt: + */ cr1 &= ~(STM32F7_I2C_CR1_RXIE | STM32F7_I2C_CR1_TXIE); + cr1 |= STM32F7_I2C_CR1_RXIE; - /* Enable RX/TX interrupt according to msg direction */ - if (msg->flags & I2C_M_RD) + /* + * Configure DMA or enable RX/TX interrupt: + * For I2C_SMBUS_BLOCK_DATA and I2C_SMBUS_BLOCK_PROC_CALL we don't use + * dma as we don't know in advance how many data will be received + */ + cr1 &= ~(STM32F7_I2C_CR1_RXIE | STM32F7_I2C_CR1_TXIE | + STM32F7_I2C_CR1_RXDMAEN | STM32F7_I2C_CR1_TXDMAEN); + + i2c_dev->use_dma = false; + if (i2c_dev->dma && f7_msg->count >= STM32F7_I2C_DMA_LEN_MIN && + f7_msg->size != I2C_SMBUS_BLOCK_DATA && + f7_msg->size != I2C_SMBUS_BLOCK_PROC_CALL) { + ret = stm32_i2c_prep_dma_xfer(i2c_dev->dev, i2c_dev->dma, + cr2 & STM32F7_I2C_CR2_RD_WRN, + f7_msg->count, f7_msg->buf, + stm32f7_i2c_dma_callback, + i2c_dev); + + if (!ret) + i2c_dev->use_dma = true; + else + dev_warn(i2c_dev->dev, "can't use DMA\n"); + } + + if (!i2c_dev->use_dma) cr1 |= STM32F7_I2C_CR1_RXIE; else - cr1 |= STM32F7_I2C_CR1_TXIE; + cr1 |= STM32F7_I2C_CR1_RXDMAEN; - /* Configure Start/Repeated Start */ + /* Configure Repeated Start */ cr2 |= STM32F7_I2C_CR2_START; /* Write configurations registers */ @@ -662,9 +1091,278 @@ static void stm32f7_i2c_xfer_msg(struct stm32f7_i2c_dev *i2c_dev, writel_relaxed(cr2, base + STM32F7_I2C_CR2); } -static void stm32f7_i2c_disable_irq(struct stm32f7_i2c_dev *i2c_dev, u32 mask) +static int stm32f7_i2c_smbus_check_pec(struct stm32f7_i2c_dev *i2c_dev) { - stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1, mask); + struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; + u8 count, internal_pec, received_pec; + + internal_pec = readl_relaxed(i2c_dev->base + STM32F7_I2C_PECR); + + switch (f7_msg->size) { + case I2C_SMBUS_BYTE: + case I2C_SMBUS_BYTE_DATA: + received_pec = f7_msg->smbus_buf[1]; + break; + case I2C_SMBUS_WORD_DATA: + case I2C_SMBUS_PROC_CALL: + received_pec = f7_msg->smbus_buf[2]; + break; + case I2C_SMBUS_BLOCK_DATA: + case I2C_SMBUS_BLOCK_PROC_CALL: + count = f7_msg->smbus_buf[0]; + received_pec = f7_msg->smbus_buf[count]; + break; + default: + dev_err(i2c_dev->dev, "Unsupported smbus protocol for PEC\n"); + return -EINVAL; + } + + if (internal_pec != received_pec) { + dev_err(i2c_dev->dev, "Bad PEC 0x%02x vs. 0x%02x\n", + internal_pec, received_pec); + return -EBADMSG; + } + + return 0; +} + +static bool stm32f7_i2c_is_addr_match(struct i2c_client *slave, u32 addcode) +{ + u32 addr; + + if (!slave) + return false; + + if (slave->flags & I2C_CLIENT_TEN) { + /* + * For 10-bit addr, addcode = 11110XY with + * X = Bit 9 of slave address + * Y = Bit 8 of slave address + */ + addr = slave->addr >> 8; + addr |= 0x78; + if (addr == addcode) + return true; + } else { + addr = slave->addr & 0x7f; + if (addr == addcode) + return true; + } + + return false; +} + +static void stm32f7_i2c_slave_start(struct stm32f7_i2c_dev *i2c_dev) +{ + struct i2c_client *slave = i2c_dev->slave_running; + void __iomem *base = i2c_dev->base; + u32 mask; + u8 value = 0; + + if (i2c_dev->slave_dir) { + /* Notify i2c slave that new read transfer is starting */ + i2c_slave_event(slave, I2C_SLAVE_READ_REQUESTED, &value); + + /* + * Disable slave TX config in case of I2C combined message + * (I2C Write followed by I2C Read) + */ + mask = STM32F7_I2C_CR2_RELOAD; + stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR2, mask); + mask = STM32F7_I2C_CR1_SBC | STM32F7_I2C_CR1_RXIE | + STM32F7_I2C_CR1_TCIE; + stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR1, mask); + + /* Enable TX empty, STOP, NACK interrupts */ + mask = STM32F7_I2C_CR1_STOPIE | STM32F7_I2C_CR1_NACKIE | + STM32F7_I2C_CR1_TXIE; + stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, mask); + + } else { + /* Notify i2c slave that new write transfer is starting */ + i2c_slave_event(slave, I2C_SLAVE_WRITE_REQUESTED, &value); + + /* Set reload mode to be able to ACK/NACK each received byte */ + mask = STM32F7_I2C_CR2_RELOAD; + stm32f7_i2c_set_bits(base + STM32F7_I2C_CR2, mask); + + /* + * Set STOP, NACK, RX empty and transfer complete interrupts.* + * Set Slave Byte Control to be able to ACK/NACK each data + * byte received + */ + mask = STM32F7_I2C_CR1_STOPIE | STM32F7_I2C_CR1_NACKIE | + STM32F7_I2C_CR1_SBC | STM32F7_I2C_CR1_RXIE | + STM32F7_I2C_CR1_TCIE; + stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, mask); + } +} + +static void stm32f7_i2c_slave_addr(struct stm32f7_i2c_dev *i2c_dev) +{ + void __iomem *base = i2c_dev->base; + u32 isr, addcode, dir, mask; + int i; + + isr = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR); + addcode = STM32F7_I2C_ISR_ADDCODE_GET(isr); + dir = isr & STM32F7_I2C_ISR_DIR; + + for (i = 0; i < STM32F7_I2C_MAX_SLAVE; i++) { + if (stm32f7_i2c_is_addr_match(i2c_dev->slave[i], addcode)) { + i2c_dev->slave_running = i2c_dev->slave[i]; + i2c_dev->slave_dir = dir; + + /* Start I2C slave processing */ + stm32f7_i2c_slave_start(i2c_dev); + + /* Clear ADDR flag */ + mask = STM32F7_I2C_ICR_ADDRCF; + writel_relaxed(mask, base + STM32F7_I2C_ICR); + break; + } + } +} + +static int stm32f7_i2c_get_slave_id(struct stm32f7_i2c_dev *i2c_dev, + struct i2c_client *slave, int *id) +{ + int i; + + for (i = 0; i < STM32F7_I2C_MAX_SLAVE; i++) { + if (i2c_dev->slave[i] == slave) { + *id = i; + return 0; + } + } + + dev_err(i2c_dev->dev, "Slave 0x%x not registered\n", slave->addr); + + return -ENODEV; +} + +static int stm32f7_i2c_get_free_slave_id(struct stm32f7_i2c_dev *i2c_dev, + struct i2c_client *slave, int *id) +{ + struct device *dev = i2c_dev->dev; + int i; + + /* + * slave[0] supports 7-bit and 10-bit slave address + * slave[1] supports 7-bit slave address only + */ + for (i = 0; i < STM32F7_I2C_MAX_SLAVE; i++) { + if (i == 1 && (slave->flags & I2C_CLIENT_PEC)) + continue; + if (!i2c_dev->slave[i]) { + *id = i; + return 0; + } + } + + dev_err(dev, "Slave 0x%x could not be registered\n", slave->addr); + + return -EINVAL; +} + +static bool stm32f7_i2c_is_slave_registered(struct stm32f7_i2c_dev *i2c_dev) +{ + int i; + + for (i = 0; i < STM32F7_I2C_MAX_SLAVE; i++) { + if (i2c_dev->slave[i]) + return true; + } + + return false; +} + +static bool stm32f7_i2c_is_slave_busy(struct stm32f7_i2c_dev *i2c_dev) +{ + int i, busy; + + busy = 0; + for (i = 0; i < STM32F7_I2C_MAX_SLAVE; i++) { + if (i2c_dev->slave[i]) + busy++; + } + + return i == busy; +} + +static irqreturn_t stm32f7_i2c_slave_isr_event(struct stm32f7_i2c_dev *i2c_dev) +{ + void __iomem *base = i2c_dev->base; + u32 cr2, status, mask; + u8 val; + int ret; + + status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR); + + /* Slave transmitter mode */ + if (status & STM32F7_I2C_ISR_TXIS) { + i2c_slave_event(i2c_dev->slave_running, + I2C_SLAVE_READ_PROCESSED, + &val); + + /* Write data byte */ + writel_relaxed(val, base + STM32F7_I2C_TXDR); + } + + /* Transfer Complete Reload for Slave receiver mode */ + if (status & STM32F7_I2C_ISR_TCR || status & STM32F7_I2C_ISR_RXNE) { + /* + * Read data byte then set NBYTES to receive next byte or NACK + * the current received byte + */ + val = readb_relaxed(i2c_dev->base + STM32F7_I2C_RXDR); + ret = i2c_slave_event(i2c_dev->slave_running, + I2C_SLAVE_WRITE_RECEIVED, + &val); + if (!ret) { + cr2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR2); + cr2 |= STM32F7_I2C_CR2_NBYTES(1); + writel_relaxed(cr2, i2c_dev->base + STM32F7_I2C_CR2); + } else { + mask = STM32F7_I2C_CR2_NACK; + stm32f7_i2c_set_bits(base + STM32F7_I2C_CR2, mask); + } + } + + /* NACK received */ + if (status & STM32F7_I2C_ISR_NACKF) { + dev_dbg(i2c_dev->dev, "<%s>: Receive NACK\n", __func__); + writel_relaxed(STM32F7_I2C_ICR_NACKCF, base + STM32F7_I2C_ICR); + } + + /* STOP received */ + if (status & STM32F7_I2C_ISR_STOPF) { + /* Disable interrupts */ + stm32f7_i2c_disable_irq(i2c_dev, STM32F7_I2C_XFER_IRQ_MASK); + + if (i2c_dev->slave_dir) { + /* + * Flush TX buffer in order to not used the byte in + * TXDR for the next transfer + */ + mask = STM32F7_I2C_ISR_TXE; + stm32f7_i2c_set_bits(base + STM32F7_I2C_ISR, mask); + } + + /* Clear STOP flag */ + writel_relaxed(STM32F7_I2C_ICR_STOPCF, base + STM32F7_I2C_ICR); + + /* Notify i2c slave that a STOP flag has been detected */ + i2c_slave_event(i2c_dev->slave_running, I2C_SLAVE_STOP, &val); + + i2c_dev->slave_running = NULL; + } + + /* Address match received */ + if (status & STM32F7_I2C_ISR_ADDR) + stm32f7_i2c_slave_addr(i2c_dev); + + return IRQ_HANDLED; } static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data) @@ -673,6 +1371,13 @@ static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data) struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; void __iomem *base = i2c_dev->base; u32 status, mask; + int ret = IRQ_HANDLED; + + /* Check if the interrupt if for a slave device */ + if (!i2c_dev->master_mode) { + ret = stm32f7_i2c_slave_isr_event(i2c_dev); + return ret; + } status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR); @@ -694,12 +1399,21 @@ static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data) /* STOP detection flag */ if (status & STM32F7_I2C_ISR_STOPF) { /* Disable interrupts */ - stm32f7_i2c_disable_irq(i2c_dev, STM32F7_I2C_ALL_IRQ_MASK); + if (stm32f7_i2c_is_slave_registered(i2c_dev)) + mask = STM32F7_I2C_XFER_IRQ_MASK; + else + mask = STM32F7_I2C_ALL_IRQ_MASK; + stm32f7_i2c_disable_irq(i2c_dev, mask); /* Clear STOP flag */ writel_relaxed(STM32F7_I2C_ICR_STOPCF, base + STM32F7_I2C_ICR); - complete(&i2c_dev->complete); + if (i2c_dev->use_dma) { + ret = IRQ_WAKE_THREAD; + } else { + i2c_dev->master_mode = false; + complete(&i2c_dev->complete); + } } /* Transfer complete */ @@ -707,6 +1421,10 @@ static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data) if (f7_msg->stop) { mask = STM32F7_I2C_CR2_STOP; stm32f7_i2c_set_bits(base + STM32F7_I2C_CR2, mask); + } else if (i2c_dev->use_dma) { + ret = IRQ_WAKE_THREAD; + } else if (f7_msg->smbus) { + stm32f7_i2c_smbus_rep_start(i2c_dev); } else { i2c_dev->msg_id++; i2c_dev->msg++; @@ -714,13 +1432,50 @@ static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data) } } + if (status & STM32F7_I2C_ISR_TCR) { + if (f7_msg->smbus) + stm32f7_i2c_smbus_reload(i2c_dev); + else + stm32f7_i2c_reload(i2c_dev); + } + + return ret; +} + +static irqreturn_t stm32f7_i2c_isr_event_thread(int irq, void *data) +{ + struct stm32f7_i2c_dev *i2c_dev = data; + struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; + struct stm32_i2c_dma *dma = i2c_dev->dma; + u32 status; + int ret; + /* - * Transfer Complete Reload: 255 data bytes have been transferred - * We have to prepare the I2C controller to transfer the remaining - * data. + * Wait for dma transfer completion before sending next message or + * notity the end of xfer to the client */ - if (status & STM32F7_I2C_ISR_TCR) - stm32f7_i2c_reload(i2c_dev); + ret = wait_for_completion_timeout(&i2c_dev->dma->dma_complete, HZ); + if (!ret) { + dev_dbg(i2c_dev->dev, "<%s>: Timed out\n", __func__); + stm32f7_i2c_disable_dma_req(i2c_dev); + dmaengine_terminate_all(dma->chan_using); + f7_msg->result = -ETIMEDOUT; + } + + status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR); + + if (status & STM32F7_I2C_ISR_TC) { + if (f7_msg->smbus) { + stm32f7_i2c_smbus_rep_start(i2c_dev); + } else { + i2c_dev->msg_id++; + i2c_dev->msg++; + stm32f7_i2c_xfer_msg(i2c_dev, i2c_dev->msg); + } + } else { + i2c_dev->master_mode = false; + complete(&i2c_dev->complete); + } return IRQ_HANDLED; } @@ -731,7 +1486,8 @@ static irqreturn_t stm32f7_i2c_isr_error(int irq, void *data) struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; void __iomem *base = i2c_dev->base; struct device *dev = i2c_dev->dev; - u32 status; + struct stm32_i2c_dma *dma = i2c_dev->dma; + u32 mask, status; status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR); @@ -739,6 +1495,7 @@ static irqreturn_t stm32f7_i2c_isr_error(int irq, void *data) if (status & STM32F7_I2C_ISR_BERR) { dev_err(dev, "<%s>: Bus error\n", __func__); writel_relaxed(STM32F7_I2C_ICR_BERRCF, base + STM32F7_I2C_ICR); + stm32f7_i2c_release_bus(&i2c_dev->adap); f7_msg->result = -EIO; } @@ -749,8 +1506,26 @@ static irqreturn_t stm32f7_i2c_isr_error(int irq, void *data) f7_msg->result = -EAGAIN; } - stm32f7_i2c_disable_irq(i2c_dev, STM32F7_I2C_ALL_IRQ_MASK); + if (status & STM32F7_I2C_ISR_PECERR) { + dev_err(dev, "<%s>: PEC error in reception\n", __func__); + writel_relaxed(STM32F7_I2C_ICR_PECCF, base + STM32F7_I2C_ICR); + f7_msg->result = -EINVAL; + } + + /* Disable interrupts */ + if (stm32f7_i2c_is_slave_registered(i2c_dev)) + mask = STM32F7_I2C_XFER_IRQ_MASK; + else + mask = STM32F7_I2C_ALL_IRQ_MASK; + stm32f7_i2c_disable_irq(i2c_dev, mask); + + /* Disable dma */ + if (i2c_dev->use_dma) { + stm32f7_i2c_disable_dma_req(i2c_dev); + dmaengine_terminate_all(dma->chan_using); + } + i2c_dev->master_mode = false; complete(&i2c_dev->complete); return IRQ_HANDLED; @@ -761,12 +1536,14 @@ static int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap, { struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(i2c_adap); struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; + struct stm32_i2c_dma *dma = i2c_dev->dma; unsigned long time_left; int ret; i2c_dev->msg = msgs; i2c_dev->msg_num = num; i2c_dev->msg_id = 0; + f7_msg->smbus = false; ret = clk_enable(i2c_dev->clk); if (ret) { @@ -787,6 +1564,8 @@ static int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap, if (!time_left) { dev_dbg(i2c_dev->dev, "Access to slave 0x%x timed out\n", i2c_dev->msg->addr); + if (i2c_dev->use_dma) + dmaengine_terminate_all(dma->chan_using); ret = -ETIMEDOUT; } @@ -796,14 +1575,209 @@ clk_free: return (ret < 0) ? ret : num; } +static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, + unsigned short flags, char read_write, + u8 command, int size, + union i2c_smbus_data *data) +{ + struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(adapter); + struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; + struct stm32_i2c_dma *dma = i2c_dev->dma; + struct device *dev = i2c_dev->dev; + unsigned long timeout; + int i, ret; + + f7_msg->addr = addr; + f7_msg->size = size; + f7_msg->read_write = read_write; + f7_msg->smbus = true; + + ret = clk_enable(i2c_dev->clk); + if (ret) { + dev_err(i2c_dev->dev, "Failed to enable clock\n"); + return ret; + } + + ret = stm32f7_i2c_wait_free_bus(i2c_dev); + if (ret) + goto clk_free; + + ret = stm32f7_i2c_smbus_xfer_msg(i2c_dev, flags, command, data); + if (ret) + goto clk_free; + + timeout = wait_for_completion_timeout(&i2c_dev->complete, + i2c_dev->adap.timeout); + ret = f7_msg->result; + if (ret) + goto clk_free; + + if (!timeout) { + dev_dbg(dev, "Access to slave 0x%x timed out\n", f7_msg->addr); + if (i2c_dev->use_dma) + dmaengine_terminate_all(dma->chan_using); + ret = -ETIMEDOUT; + goto clk_free; + } + + /* Check PEC */ + if ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK && read_write) { + ret = stm32f7_i2c_smbus_check_pec(i2c_dev); + if (ret) + goto clk_free; + } + + if (read_write && size != I2C_SMBUS_QUICK) { + switch (size) { + case I2C_SMBUS_BYTE: + case I2C_SMBUS_BYTE_DATA: + data->byte = f7_msg->smbus_buf[0]; + break; + case I2C_SMBUS_WORD_DATA: + case I2C_SMBUS_PROC_CALL: + data->word = f7_msg->smbus_buf[0] | + (f7_msg->smbus_buf[1] << 8); + break; + case I2C_SMBUS_BLOCK_DATA: + case I2C_SMBUS_BLOCK_PROC_CALL: + for (i = 0; i <= f7_msg->smbus_buf[0]; i++) + data->block[i] = f7_msg->smbus_buf[i]; + break; + default: + dev_err(dev, "Unsupported smbus transaction\n"); + ret = -EINVAL; + } + } + +clk_free: + clk_disable(i2c_dev->clk); + return ret; +} + +static int stm32f7_i2c_reg_slave(struct i2c_client *slave) +{ + struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(slave->adapter); + void __iomem *base = i2c_dev->base; + struct device *dev = i2c_dev->dev; + u32 oar1, oar2, mask; + int id, ret; + + if (slave->flags & I2C_CLIENT_PEC) { + dev_err(dev, "SMBus PEC not supported in slave mode\n"); + return -EINVAL; + } + + if (stm32f7_i2c_is_slave_busy(i2c_dev)) { + dev_err(dev, "Too much slave registered\n"); + return -EBUSY; + } + + ret = stm32f7_i2c_get_free_slave_id(i2c_dev, slave, &id); + if (ret) + return ret; + + if (!(stm32f7_i2c_is_slave_registered(i2c_dev))) { + ret = clk_enable(i2c_dev->clk); + if (ret) { + dev_err(dev, "Failed to enable clock\n"); + return ret; + } + } + + if (id == 0) { + /* Configure Own Address 1 */ + oar1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR1); + oar1 &= ~STM32F7_I2C_OAR1_MASK; + if (slave->flags & I2C_CLIENT_TEN) { + oar1 |= STM32F7_I2C_OAR1_OA1_10(slave->addr); + oar1 |= STM32F7_I2C_OAR1_OA1MODE; + } else { + oar1 |= STM32F7_I2C_OAR1_OA1_7(slave->addr); + } + oar1 |= STM32F7_I2C_OAR1_OA1EN; + i2c_dev->slave[id] = slave; + writel_relaxed(oar1, i2c_dev->base + STM32F7_I2C_OAR1); + } else if (id == 1) { + /* Configure Own Address 2 */ + oar2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR2); + oar2 &= ~STM32F7_I2C_OAR2_MASK; + if (slave->flags & I2C_CLIENT_TEN) { + ret = -EOPNOTSUPP; + goto exit; + } + + oar2 |= STM32F7_I2C_OAR2_OA2_7(slave->addr); + oar2 |= STM32F7_I2C_OAR2_OA2EN; + i2c_dev->slave[id] = slave; + writel_relaxed(oar2, i2c_dev->base + STM32F7_I2C_OAR2); + } else { + ret = -ENODEV; + goto exit; + } + + /* Enable ACK */ + stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR2, STM32F7_I2C_CR2_NACK); + + /* Enable Address match interrupt, error interrupt and enable I2C */ + mask = STM32F7_I2C_CR1_ADDRIE | STM32F7_I2C_CR1_ERRIE | + STM32F7_I2C_CR1_PE; + stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, mask); + + return 0; + +exit: + if (!(stm32f7_i2c_is_slave_registered(i2c_dev))) + clk_disable(i2c_dev->clk); + + return ret; +} + +static int stm32f7_i2c_unreg_slave(struct i2c_client *slave) +{ + struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(slave->adapter); + void __iomem *base = i2c_dev->base; + u32 mask; + int id, ret; + + ret = stm32f7_i2c_get_slave_id(i2c_dev, slave, &id); + if (ret) + return ret; + + WARN_ON(!i2c_dev->slave[id]); + + if (id == 0) { + mask = STM32F7_I2C_OAR1_OA1EN; + stm32f7_i2c_clr_bits(base + STM32F7_I2C_OAR1, mask); + } else { + mask = STM32F7_I2C_OAR2_OA2EN; + stm32f7_i2c_clr_bits(base + STM32F7_I2C_OAR2, mask); + } + + i2c_dev->slave[id] = NULL; + + if (!(stm32f7_i2c_is_slave_registered(i2c_dev))) { + stm32f7_i2c_disable_irq(i2c_dev, STM32F7_I2C_ALL_IRQ_MASK); + clk_disable(i2c_dev->clk); + } + + return 0; +} + static u32 stm32f7_i2c_func(struct i2c_adapter *adap) { - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; + return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SLAVE | + I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL | + I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_PEC; } static struct i2c_algorithm stm32f7_i2c_algo = { .master_xfer = stm32f7_i2c_xfer, + .smbus_xfer = stm32f7_i2c_smbus_xfer, .functionality = stm32f7_i2c_func, + .reg_slave = stm32f7_i2c_reg_slave, + .unreg_slave = stm32f7_i2c_unreg_slave, }; static int stm32f7_i2c_probe(struct platform_device *pdev) @@ -815,6 +1789,7 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) u32 irq_error, irq_event, clk_rate, rise_time, fall_time; struct i2c_adapter *adap; struct reset_control *rst; + dma_addr_t phy_addr; int ret; i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); @@ -825,6 +1800,7 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) i2c_dev->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(i2c_dev->base)) return PTR_ERR(i2c_dev->base); + phy_addr = (dma_addr_t)res->start; irq_event = irq_of_parse_and_map(np, 0); if (!irq_event) { @@ -871,8 +1847,11 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) i2c_dev->dev = &pdev->dev; - ret = devm_request_irq(&pdev->dev, irq_event, stm32f7_i2c_isr_event, 0, - pdev->name, i2c_dev); + ret = devm_request_threaded_irq(&pdev->dev, irq_event, + stm32f7_i2c_isr_event, + stm32f7_i2c_isr_event_thread, + IRQF_ONESHOT, + pdev->name, i2c_dev); if (ret) { dev_err(&pdev->dev, "Failed to request irq event %i\n", irq_event); @@ -924,6 +1903,11 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) init_completion(&i2c_dev->complete); + /* Init DMA config if supported */ + i2c_dev->dma = stm32_i2c_dma_request(i2c_dev->dev, phy_addr, + STM32F7_I2C_TXDR, + STM32F7_I2C_RXDR); + ret = i2c_add_adapter(adap); if (ret) goto clk_free; @@ -946,6 +1930,11 @@ static int stm32f7_i2c_remove(struct platform_device *pdev) { struct stm32f7_i2c_dev *i2c_dev = platform_get_drvdata(pdev); + if (i2c_dev->dma) { + stm32_i2c_dma_free(i2c_dev->dma); + i2c_dev->dma = NULL; + } + i2c_del_adapter(&i2c_dev->adap); clk_unprepare(i2c_dev->clk); diff --git a/drivers/i2c/busses/i2c-stu300.c b/drivers/i2c/busses/i2c-stu300.c index dc63236b45b2..e866c481bfc3 100644 --- a/drivers/i2c/busses/i2c-stu300.c +++ b/drivers/i2c/busses/i2c-stu300.c @@ -602,20 +602,24 @@ static int stu300_send_address(struct stu300_dev *dev, u32 val; int ret; - if (msg->flags & I2C_M_TEN) + if (msg->flags & I2C_M_TEN) { /* This is probably how 10 bit addresses look */ val = (0xf0 | (((u32) msg->addr & 0x300) >> 7)) & I2C_DR_D_MASK; - else - val = ((msg->addr << 1) & I2C_DR_D_MASK); + if (msg->flags & I2C_M_RD) + /* This is the direction bit */ + val |= 0x01; + } else { + val = i2c_8bit_addr_from_msg(msg); + } - if (msg->flags & I2C_M_RD) { - /* This is the direction bit */ - val |= 0x01; - if (resend) + if (resend) { + if (msg->flags & I2C_M_RD) dev_dbg(&dev->pdev->dev, "read resend\n"); - } else if (resend) - dev_dbg(&dev->pdev->dev, "write resend\n"); + else + dev_dbg(&dev->pdev->dev, "write resend\n"); + } + stu300_wr8(val, dev->virtbase + I2C_DR); /* For 10bit addressing, await 10bit request (EVENT 9) */ diff --git a/drivers/i2c/busses/i2c-synquacer.c b/drivers/i2c/busses/i2c-synquacer.c index a021f866d8c2..915f5edbab33 100644 --- a/drivers/i2c/busses/i2c-synquacer.c +++ b/drivers/i2c/busses/i2c-synquacer.c @@ -509,7 +509,7 @@ static int synquacer_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, dev_dbg(i2c->dev, "calculated timeout %d ms\n", i2c->timeout_ms); - for (retry = 0; retry < adap->retries; retry++) { + for (retry = 0; retry <= adap->retries; retry++) { ret = synquacer_i2c_doxfer(i2c, msgs, num); if (ret != -EAGAIN) return ret; diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 60292d243e24..5fccd1f1bca8 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -173,7 +173,6 @@ struct tegra_i2c_hw_feature { * @msg_buf_remaining: size of unsent data in the message buffer * @msg_read: identifies read transfers * @bus_clk_rate: current i2c bus clock rate - * @is_suspended: prevents i2c controller accesses after suspend is called */ struct tegra_i2c_dev { struct device *dev; @@ -194,7 +193,6 @@ struct tegra_i2c_dev { int msg_read; u32 bus_clk_rate; u16 clk_divisor_non_hs_mode; - bool is_suspended; bool is_multimaster_mode; spinlock_t xfer_lock; }; @@ -734,9 +732,6 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int i; int ret = 0; - if (i2c_dev->is_suspended) - return -EBUSY; - ret = pm_runtime_get_sync(i2c_dev->dev); if (ret < 0) { dev_err(i2c_dev->dev, "runtime resume failed %d\n", ret); @@ -1051,37 +1046,9 @@ static int tegra_i2c_remove(struct platform_device *pdev) } #ifdef CONFIG_PM_SLEEP -static int tegra_i2c_suspend(struct device *dev) -{ - struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev); - - i2c_lock_adapter(&i2c_dev->adapter); - i2c_dev->is_suspended = true; - i2c_unlock_adapter(&i2c_dev->adapter); - - return 0; -} - -static int tegra_i2c_resume(struct device *dev) -{ - struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev); - int ret; - - i2c_lock_adapter(&i2c_dev->adapter); - - ret = tegra_i2c_init(i2c_dev); - if (!ret) - i2c_dev->is_suspended = false; - - i2c_unlock_adapter(&i2c_dev->adapter); - - return ret; -} - static const struct dev_pm_ops tegra_i2c_pm = { SET_RUNTIME_PM_OPS(tegra_i2c_runtime_suspend, tegra_i2c_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(tegra_i2c_suspend, tegra_i2c_resume) }; #define TEGRA_I2C_PM (&tegra_i2c_pm) #else diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index c80527816ad0..9a71e50d21f1 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -33,7 +33,7 @@ #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/wait.h> -#include <linux/i2c-xiic.h> +#include <linux/platform_data/i2c-xiic.h> #include <linux/io.h> #include <linux/slab.h> #include <linux/of.h> @@ -143,12 +143,6 @@ struct xiic_i2c { #define XIIC_TX_RX_INTERRUPTS (XIIC_INTR_RX_FULL_MASK | XIIC_TX_INTERRUPTS) -/* The following constants are used with the following macros to specify the - * operation, a read or write operation. - */ -#define XIIC_READ_OPERATION 1 -#define XIIC_WRITE_OPERATION 0 - /* * Tx Fifo upper bit masks. */ @@ -415,7 +409,7 @@ static irqreturn_t xiic_process(int irq, void *dev_id) clr |= XIIC_INTR_RX_FULL_MASK; if (!i2c->rx_msg) { dev_dbg(i2c->adap.dev.parent, - "%s unexpexted RX IRQ\n", __func__); + "%s unexpected RX IRQ\n", __func__); xiic_clear_rx_fifo(i2c); goto out; } @@ -470,7 +464,7 @@ static irqreturn_t xiic_process(int irq, void *dev_id) if (!i2c->tx_msg) { dev_dbg(i2c->adap.dev.parent, - "%s unexpexted TX IRQ\n", __func__); + "%s unexpected TX IRQ\n", __func__); goto out; } @@ -556,8 +550,7 @@ static void xiic_start_recv(struct xiic_i2c *i2c) if (!(msg->flags & I2C_M_NOSTART)) /* write the address */ xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, - (msg->addr << 1) | XIIC_READ_OPERATION | - XIIC_TX_DYN_START_MASK); + i2c_8bit_addr_from_msg(msg) | XIIC_TX_DYN_START_MASK); xiic_irq_clr_en(i2c, XIIC_INTR_BNB_MASK); @@ -585,7 +578,7 @@ static void xiic_start_send(struct xiic_i2c *i2c) if (!(msg->flags & I2C_M_NOSTART)) { /* write the address */ - u16 data = ((msg->addr << 1) & 0xfe) | XIIC_WRITE_OPERATION | + u16 data = i2c_8bit_addr_from_msg(msg) | XIIC_TX_DYN_START_MASK; if ((i2c->nmsgs == 1) && msg->len == 0) /* no data and last message -> add STOP */ diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c index eb8913eba0c5..1f41a4f89c08 100644 --- a/drivers/i2c/busses/i2c-xlp9xx.c +++ b/drivers/i2c/busses/i2c-xlp9xx.c @@ -10,6 +10,7 @@ #include <linux/clk.h> #include <linux/completion.h> #include <linux/i2c.h> +#include <linux/i2c-smbus.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/io.h> @@ -84,6 +85,8 @@ struct xlp9xx_i2c_dev { struct device *dev; struct i2c_adapter adapter; struct completion msg_complete; + struct i2c_smbus_alert_setup alert_data; + struct i2c_client *ara; int irq; bool msg_read; bool len_recv; @@ -155,9 +158,30 @@ static void xlp9xx_i2c_fill_tx_fifo(struct xlp9xx_i2c_dev *priv) priv->msg_buf += len; } +static void xlp9xx_i2c_update_rlen(struct xlp9xx_i2c_dev *priv) +{ + u32 val, len; + + /* + * Update receive length. Re-read len to get the latest value, + * and then add 4 to have a minimum value that can be safely + * written. This is to account for the byte read above, the + * transfer in progress and any delays in the register I/O + */ + val = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_CTRL); + len = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_FIFOWCNT) & + XLP9XX_I2C_FIFO_WCNT_MASK; + len = max_t(u32, priv->msg_len, len + 4); + if (len >= I2C_SMBUS_BLOCK_MAX + 2) + return; + val = (val & ~XLP9XX_I2C_CTRL_MCTLEN_MASK) | + (len << XLP9XX_I2C_CTRL_MCTLEN_SHIFT); + xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, val); +} + static void xlp9xx_i2c_drain_rx_fifo(struct xlp9xx_i2c_dev *priv) { - u32 len, i, val; + u32 len, i; u8 rlen, *buf = priv->msg_buf; len = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_FIFOWCNT) & @@ -167,21 +191,20 @@ static void xlp9xx_i2c_drain_rx_fifo(struct xlp9xx_i2c_dev *priv) if (priv->len_recv) { /* read length byte */ rlen = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_MRXFIFO); - *buf++ = rlen; - len--; - - if (priv->client_pec) - ++rlen; - /* update remaining bytes and message length */ - priv->msg_buf_remaining = rlen; - priv->msg_len = rlen + 1; + if (rlen > I2C_SMBUS_BLOCK_MAX || rlen == 0) { + rlen = 0; /*abort transfer */ + priv->msg_buf_remaining = 0; + priv->msg_len = 0; + } else { + *buf++ = rlen; + if (priv->client_pec) + ++rlen; /* account for error check byte */ + /* update remaining bytes and message length */ + priv->msg_buf_remaining = rlen; + priv->msg_len = rlen + 1; + } + xlp9xx_i2c_update_rlen(priv); priv->len_recv = false; - - /* Update transfer length to read only actual data */ - val = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_CTRL); - val = (val & ~XLP9XX_I2C_CTRL_MCTLEN_MASK) | - ((rlen + 1) << XLP9XX_I2C_CTRL_MCTLEN_SHIFT); - xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, val); } else { len = min(priv->msg_buf_remaining, len); for (i = 0; i < len; i++, buf++) @@ -300,10 +323,6 @@ static int xlp9xx_i2c_xfer_msg(struct xlp9xx_i2c_dev *priv, struct i2c_msg *msg, xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_MFIFOCTRL, XLP9XX_I2C_MFIFOCTRL_RST); - /* set FIFO threshold if reading */ - if (priv->msg_read) - xlp9xx_i2c_update_rx_fifo_thres(priv); - /* set slave addr */ xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_SLAVEADDR, (msg->addr << XLP9XX_I2C_SLAVEADDR_ADDR_SHIFT) | @@ -322,9 +341,13 @@ static int xlp9xx_i2c_xfer_msg(struct xlp9xx_i2c_dev *priv, struct i2c_msg *msg, val &= ~XLP9XX_I2C_CTRL_ADDMODE; priv->len_recv = msg->flags & I2C_M_RECV_LEN; - len = priv->len_recv ? XLP9XX_I2C_FIFO_SIZE : msg->len; + len = priv->len_recv ? I2C_SMBUS_BLOCK_MAX + 2 : msg->len; priv->client_pec = msg->flags & I2C_CLIENT_PEC; + /* set FIFO threshold if reading */ + if (priv->msg_read) + xlp9xx_i2c_update_rx_fifo_thres(priv); + /* set data length to be transferred */ val = (val & ~XLP9XX_I2C_CTRL_MCTLEN_MASK) | (len << XLP9XX_I2C_CTRL_MCTLEN_SHIFT); @@ -378,8 +401,11 @@ static int xlp9xx_i2c_xfer_msg(struct xlp9xx_i2c_dev *priv, struct i2c_msg *msg, } /* update msg->len with actual received length */ - if (msg->flags & I2C_M_RECV_LEN) + if (msg->flags & I2C_M_RECV_LEN) { + if (!priv->msg_len) + return -EPROTO; msg->len = priv->msg_len; + } return 0; } @@ -447,6 +473,19 @@ static int xlp9xx_i2c_get_frequency(struct platform_device *pdev, return 0; } +static int xlp9xx_i2c_smbus_setup(struct xlp9xx_i2c_dev *priv, + struct platform_device *pdev) +{ + if (!priv->alert_data.irq) + return -EINVAL; + + priv->ara = i2c_setup_smbus_alert(&priv->adapter, &priv->alert_data); + if (!priv->ara) + return -ENODEV; + + return 0; +} + static int xlp9xx_i2c_probe(struct platform_device *pdev) { struct xlp9xx_i2c_dev *priv; @@ -467,6 +506,10 @@ static int xlp9xx_i2c_probe(struct platform_device *pdev) dev_err(&pdev->dev, "invalid irq!\n"); return priv->irq; } + /* SMBAlert irq */ + priv->alert_data.irq = platform_get_irq(pdev, 1); + if (priv->alert_data.irq <= 0) + priv->alert_data.irq = 0; xlp9xx_i2c_get_frequency(pdev, priv); xlp9xx_i2c_init(priv); @@ -493,6 +536,10 @@ static int xlp9xx_i2c_probe(struct platform_device *pdev) if (err) return err; + err = xlp9xx_i2c_smbus_setup(priv, pdev); + if (err) + dev_dbg(&pdev->dev, "No active SMBus alert %d\n", err); + platform_set_drvdata(pdev, priv); dev_dbg(&pdev->dev, "I2C bus:%d added\n", priv->adapter.nr); diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index a17f46a95f73..31d16ada6e7d 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -717,10 +717,6 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) client->adapter = adap; client->dev.platform_data = info->platform_data; - - if (info->archdata) - client->dev.archdata = *info->archdata; - client->flags = info->flags; client->addr = info->addr; @@ -746,7 +742,7 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) client->dev.parent = &client->adapter->dev; client->dev.bus = &i2c_bus_type; client->dev.type = &i2c_client_type; - client->dev.of_node = info->of_node; + client->dev.of_node = of_node_get(info->of_node); client->dev.fwnode = info->fwnode; i2c_dev_set_name(adap, client, info); @@ -757,7 +753,7 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) dev_err(&adap->dev, "Failed to add properties to client %s: %d\n", client->name, status); - goto out_err; + goto out_err_put_of_node; } } @@ -773,6 +769,8 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) out_free_props: if (info->properties) device_remove_properties(&client->dev); +out_err_put_of_node: + of_node_put(info->of_node); out_err: dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x (%d)\n", diff --git a/drivers/i2c/i2c-core-of.c b/drivers/i2c/i2c-core-of.c index c405270a98b4..6cb7ad608bcd 100644 --- a/drivers/i2c/i2c-core-of.c +++ b/drivers/i2c/i2c-core-of.c @@ -22,53 +22,64 @@ #include "i2c-core.h" -static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap, - struct device_node *node) +int of_i2c_get_board_info(struct device *dev, struct device_node *node, + struct i2c_board_info *info) { - struct i2c_client *client; - struct i2c_board_info info = {}; - struct dev_archdata dev_ad = {}; u32 addr; int ret; - dev_dbg(&adap->dev, "of_i2c: register %pOF\n", node); + memset(info, 0, sizeof(*info)); - if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) { - dev_err(&adap->dev, "of_i2c: modalias failure on %pOF\n", - node); - return ERR_PTR(-EINVAL); + if (of_modalias_node(node, info->type, sizeof(info->type)) < 0) { + dev_err(dev, "of_i2c: modalias failure on %pOF\n", node); + return -EINVAL; } ret = of_property_read_u32(node, "reg", &addr); if (ret) { - dev_err(&adap->dev, "of_i2c: invalid reg on %pOF\n", node); - return ERR_PTR(ret); + dev_err(dev, "of_i2c: invalid reg on %pOF\n", node); + return ret; } if (addr & I2C_TEN_BIT_ADDRESS) { addr &= ~I2C_TEN_BIT_ADDRESS; - info.flags |= I2C_CLIENT_TEN; + info->flags |= I2C_CLIENT_TEN; } if (addr & I2C_OWN_SLAVE_ADDRESS) { addr &= ~I2C_OWN_SLAVE_ADDRESS; - info.flags |= I2C_CLIENT_SLAVE; + info->flags |= I2C_CLIENT_SLAVE; } - info.addr = addr; - info.archdata = &dev_ad; - info.of_node = of_node_get(node); + info->addr = addr; + info->of_node = node; if (of_property_read_bool(node, "host-notify")) - info.flags |= I2C_CLIENT_HOST_NOTIFY; + info->flags |= I2C_CLIENT_HOST_NOTIFY; if (of_get_property(node, "wakeup-source", NULL)) - info.flags |= I2C_CLIENT_WAKE; + info->flags |= I2C_CLIENT_WAKE; + + return 0; +} +EXPORT_SYMBOL_GPL(of_i2c_get_board_info); + +static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap, + struct device_node *node) +{ + struct i2c_client *client; + struct i2c_board_info info; + int ret; + + dev_dbg(&adap->dev, "of_i2c: register %pOF\n", node); + + ret = of_i2c_get_board_info(&adap->dev, node, &info); + if (ret) + return ERR_PTR(ret); client = i2c_new_device(adap, &info); if (!client) { dev_err(&adap->dev, "of_i2c: Failure registering %pOF\n", node); - of_node_put(node); return ERR_PTR(-EINVAL); } return client; diff --git a/drivers/i2c/i2c-core-smbus.c b/drivers/i2c/i2c-core-smbus.c index b5aec33002c3..f3f683041e7f 100644 --- a/drivers/i2c/i2c-core-smbus.c +++ b/drivers/i2c/i2c-core-smbus.c @@ -466,6 +466,8 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, status = i2c_transfer(adapter, msg, num); if (status < 0) return status; + if (status != num) + return -EIO; /* Check PEC if last message is a read */ if (i && (msg[num-1].flags & I2C_M_RD)) { diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index 1667b6e7674f..1aca742fde4a 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -244,7 +244,7 @@ static noinline int i2cdev_ioctl_rdwr(struct i2c_client *client, u8 __user **data_ptrs; int i, res; - data_ptrs = kmalloc(nmsgs * sizeof(u8 __user *), GFP_KERNEL); + data_ptrs = kmalloc_array(nmsgs, sizeof(u8 __user *), GFP_KERNEL); if (data_ptrs == NULL) { kfree(msgs); return -ENOMEM; diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c index 9669ca4937b8..300ab4b672e4 100644 --- a/drivers/i2c/i2c-mux.c +++ b/drivers/i2c/i2c-mux.c @@ -418,7 +418,7 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc, snprintf(symlink_name, sizeof(symlink_name), "channel-%u", chan_id); WARN(sysfs_create_link(&muxc->dev->kobj, &priv->adap.dev.kobj, symlink_name), - "can't create symlink for channel %u\n", chan_id); + "can't create symlink to channel %u\n", chan_id); dev_info(&parent->dev, "Added multiplexed i2c bus %d\n", i2c_adapter_id(&priv->adap)); diff --git a/drivers/i2c/i2c-stub.c b/drivers/i2c/i2c-stub.c index 4a9ad91c5ba3..f31ec0861979 100644 --- a/drivers/i2c/i2c-stub.c +++ b/drivers/i2c/i2c-stub.c @@ -338,8 +338,9 @@ static int __init i2c_stub_allocate_banks(int i) chip->bank_mask >>= 1; } - chip->bank_words = kzalloc(chip->bank_mask * chip->bank_size * - sizeof(u16), GFP_KERNEL); + chip->bank_words = kcalloc(chip->bank_mask * chip->bank_size, + sizeof(u16), + GFP_KERNEL); if (!chip->bank_words) return -ENOMEM; diff --git a/drivers/i2c/muxes/i2c-demux-pinctrl.c b/drivers/i2c/muxes/i2c-demux-pinctrl.c index 33ce032cb701..035032e20327 100644 --- a/drivers/i2c/muxes/i2c-demux-pinctrl.c +++ b/drivers/i2c/muxes/i2c-demux-pinctrl.c @@ -18,6 +18,7 @@ #include <linux/of.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/slab.h> #include <linux/sysfs.h> @@ -105,7 +106,7 @@ static int i2c_demux_activate_master(struct i2c_demux_pinctrl_priv *priv, u32 ne priv->cur_adap.owner = THIS_MODULE; priv->cur_adap.algo = &priv->algo; priv->cur_adap.algo_data = priv; - priv->cur_adap.dev.parent = priv->dev; + priv->cur_adap.dev.parent = &adap->dev; priv->cur_adap.class = adap->class; priv->cur_adap.retries = adap->retries; priv->cur_adap.timeout = adap->timeout; @@ -254,6 +255,8 @@ static int i2c_demux_pinctrl_probe(struct platform_device *pdev) platform_set_drvdata(pdev, priv); + pm_runtime_no_callbacks(&pdev->dev); + /* switch to first parent as active master */ i2c_demux_activate_master(priv, 0); diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index 1a9973ede443..401308e3d036 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -10,7 +10,7 @@ #include <linux/i2c.h> #include <linux/i2c-mux.h> -#include <linux/i2c-mux-gpio.h> +#include <linux/platform_data/i2c-mux-gpio.h> #include <linux/platform_device.h> #include <linux/module.h> #include <linux/slab.h> @@ -88,8 +88,8 @@ static int i2c_mux_gpio_probe_dt(struct gpiomux *mux, mux->data.n_values = of_get_child_count(np); - values = devm_kzalloc(&pdev->dev, - sizeof(*mux->data.values) * mux->data.n_values, + values = devm_kcalloc(&pdev->dev, + mux->data.n_values, sizeof(*mux->data.values), GFP_KERNEL); if (!values) { dev_err(&pdev->dev, "Cannot allocate values array"); @@ -111,8 +111,9 @@ static int i2c_mux_gpio_probe_dt(struct gpiomux *mux, return -EINVAL; } - gpios = devm_kzalloc(&pdev->dev, - sizeof(*mux->data.gpios) * mux->data.n_gpios, GFP_KERNEL); + gpios = devm_kcalloc(&pdev->dev, + mux->data.n_gpios, sizeof(*mux->data.gpios), + GFP_KERNEL); if (!gpios) { dev_err(&pdev->dev, "Cannot allocate gpios array"); return -ENOMEM; diff --git a/drivers/i2c/muxes/i2c-mux-ltc4306.c b/drivers/i2c/muxes/i2c-mux-ltc4306.c index 311b1cced0c0..a9af93259b19 100644 --- a/drivers/i2c/muxes/i2c-mux-ltc4306.c +++ b/drivers/i2c/muxes/i2c-mux-ltc4306.c @@ -206,8 +206,7 @@ static const struct of_device_id ltc4306_of_match[] = { }; MODULE_DEVICE_TABLE(of, ltc4306_of_match); -static int ltc4306_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ltc4306_probe(struct i2c_client *client) { struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); const struct chip_desc *chip; @@ -221,7 +220,7 @@ static int ltc4306_probe(struct i2c_client *client, chip = of_device_get_match_data(&client->dev); if (!chip) - chip = &chips[id->driver_data]; + chip = &chips[i2c_match_id(ltc4306_id, client)->driver_data]; idle_disc = device_property_read_bool(&client->dev, "i2c-mux-idle-disconnect"); @@ -310,7 +309,7 @@ static struct i2c_driver ltc4306_driver = { .name = "ltc4306", .of_match_table = of_match_ptr(ltc4306_of_match), }, - .probe = ltc4306_probe, + .probe_new = ltc4306_probe, .remove = ltc4306_remove, .id_table = ltc4306_id, }; diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index 09bafd3e68fa..fbc748027087 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -36,6 +36,7 @@ */ #include <linux/device.h> +#include <linux/delay.h> #include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/i2c-mux.h> @@ -373,7 +374,6 @@ static int pca954x_probe(struct i2c_client *client, int num, force, class; struct i2c_mux_core *muxc; struct pca954x *data; - const struct of_device_id *match; int ret; if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE)) @@ -389,15 +389,19 @@ static int pca954x_probe(struct i2c_client *client, i2c_set_clientdata(client, muxc); data->client = client; - /* Get the mux out of reset if a reset GPIO is specified. */ - gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_LOW); + /* Reset the mux if a reset GPIO is specified. */ + gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(gpio)) return PTR_ERR(gpio); + if (gpio) { + udelay(1); + gpiod_set_value_cansleep(gpio, 0); + /* Give the chip some time to recover. */ + udelay(1); + } - match = of_match_device(of_match_ptr(pca954x_of_match), &client->dev); - if (match) - data->chip = of_device_get_match_data(&client->dev); - else + data->chip = of_device_get_match_data(&client->dev); + if (!data->chip) data->chip = &chips[id->driver_data]; if (data->chip->id.manufacturer_id != I2C_DEVICE_ID_NONE) { diff --git a/drivers/i2c/muxes/i2c-mux-reg.c b/drivers/i2c/muxes/i2c-mux-reg.c index c948e5a4cb04..5653295b01cd 100644 --- a/drivers/i2c/muxes/i2c-mux-reg.c +++ b/drivers/i2c/muxes/i2c-mux-reg.c @@ -124,13 +124,11 @@ static int i2c_mux_reg_probe_dt(struct regmux *mux, } mux->data.write_only = of_property_read_bool(np, "write-only"); - values = devm_kzalloc(&pdev->dev, - sizeof(*mux->data.values) * mux->data.n_values, + values = devm_kcalloc(&pdev->dev, + mux->data.n_values, sizeof(*mux->data.values), GFP_KERNEL); - if (!values) { - dev_err(&pdev->dev, "Cannot allocate values array"); + if (!values) return -ENOMEM; - } for_each_child_of_node(np, child) { of_property_read_u32(child, "reg", values + i); diff --git a/drivers/ide/hpt366.c b/drivers/ide/hpt366.c index 4b5dc0162e67..e52c58c29d9a 100644 --- a/drivers/ide/hpt366.c +++ b/drivers/ide/hpt366.c @@ -1455,7 +1455,7 @@ static int hpt366_init_one(struct pci_dev *dev, const struct pci_device_id *id) if (info == &hpt36x || info == &hpt374) dev2 = pci_get_slot(dev->bus, dev->devfn + 1); - dyn_info = kzalloc(sizeof(*dyn_info) * (dev2 ? 2 : 1), GFP_KERNEL); + dyn_info = kcalloc(dev2 ? 2 : 1, sizeof(*dyn_info), GFP_KERNEL); if (dyn_info == NULL) { printk(KERN_ERR "%s %s: out of memory!\n", d.name, pci_name(dev)); diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 56d7bc228cb3..416a2f353071 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -985,8 +985,9 @@ static int hwif_init(ide_hwif_t *hwif) if (!hwif->sg_max_nents) hwif->sg_max_nents = PRD_ENTRIES; - hwif->sg_table = kmalloc(sizeof(struct scatterlist)*hwif->sg_max_nents, - GFP_KERNEL); + hwif->sg_table = kmalloc_array(hwif->sg_max_nents, + sizeof(struct scatterlist), + GFP_KERNEL); if (!hwif->sg_table) { printk(KERN_ERR "%s: unable to allocate SG table.\n", hwif->name); goto out; diff --git a/drivers/ide/it821x.c b/drivers/ide/it821x.c index 04029d18a696..36a64c8ea575 100644 --- a/drivers/ide/it821x.c +++ b/drivers/ide/it821x.c @@ -652,7 +652,7 @@ static int it821x_init_one(struct pci_dev *dev, const struct pci_device_id *id) struct it821x_dev *itdevs; int rc; - itdevs = kzalloc(2 * sizeof(*itdevs), GFP_KERNEL); + itdevs = kcalloc(2, sizeof(*itdevs), GFP_KERNEL); if (itdevs == NULL) { printk(KERN_ERR DRV_NAME " %s: out of memory\n", pci_name(dev)); return -ENOMEM; diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index 71a5ee652b79..44b516863c9d 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -624,8 +624,8 @@ static int at91_adc_trigger_init(struct iio_dev *idev) struct at91_adc_state *st = iio_priv(idev); int i, ret; - st->trig = devm_kzalloc(&idev->dev, - st->trigger_number * sizeof(*st->trig), + st->trig = devm_kcalloc(&idev->dev, + st->trigger_number, sizeof(*st->trig), GFP_KERNEL); if (st->trig == NULL) { @@ -908,7 +908,8 @@ static int at91_adc_probe_dt(struct at91_adc_state *st, st->registers = &st->caps->registers; st->num_channels = st->caps->num_channels; st->trigger_number = of_get_child_count(node); - st->trigger_list = devm_kzalloc(&idev->dev, st->trigger_number * + st->trigger_list = devm_kcalloc(&idev->dev, + st->trigger_number, sizeof(struct at91_adc_trigger), GFP_KERNEL); if (!st->trigger_list) { diff --git a/drivers/iio/adc/max1027.c b/drivers/iio/adc/max1027.c index 375da6491499..311c1a89c329 100644 --- a/drivers/iio/adc/max1027.c +++ b/drivers/iio/adc/max1027.c @@ -422,8 +422,8 @@ static int max1027_probe(struct spi_device *spi) indio_dev->num_channels = st->info->num_channels; indio_dev->available_scan_masks = st->info->available_scan_masks; - st->buffer = devm_kmalloc(&indio_dev->dev, - indio_dev->num_channels * 2, + st->buffer = devm_kmalloc_array(&indio_dev->dev, + indio_dev->num_channels, 2, GFP_KERNEL); if (st->buffer == NULL) { dev_err(&indio_dev->dev, "Can't allocate buffer\n"); diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c index 7f1848dac9bf..7fb4f525714a 100644 --- a/drivers/iio/adc/max1363.c +++ b/drivers/iio/adc/max1363.c @@ -1453,8 +1453,10 @@ static int max1363_alloc_scan_masks(struct iio_dev *indio_dev) int i; masks = devm_kzalloc(&indio_dev->dev, - BITS_TO_LONGS(MAX1363_MAX_CHANNELS) * sizeof(long) * - (st->chip_info->num_modes + 1), GFP_KERNEL); + array3_size(BITS_TO_LONGS(MAX1363_MAX_CHANNELS), + sizeof(long), + st->chip_info->num_modes + 1), + GFP_KERNEL); if (!masks) return -ENOMEM; diff --git a/drivers/iio/adc/twl6030-gpadc.c b/drivers/iio/adc/twl6030-gpadc.c index dc83f8f6c3d3..e470510e76ea 100644 --- a/drivers/iio/adc/twl6030-gpadc.c +++ b/drivers/iio/adc/twl6030-gpadc.c @@ -898,9 +898,10 @@ static int twl6030_gpadc_probe(struct platform_device *pdev) gpadc = iio_priv(indio_dev); - gpadc->twl6030_cal_tbl = devm_kzalloc(dev, - sizeof(*gpadc->twl6030_cal_tbl) * - pdata->nchannels, GFP_KERNEL); + gpadc->twl6030_cal_tbl = devm_kcalloc(dev, + pdata->nchannels, + sizeof(*gpadc->twl6030_cal_tbl), + GFP_KERNEL); if (!gpadc->twl6030_cal_tbl) return -ENOMEM; diff --git a/drivers/iio/dac/ad5592r-base.c b/drivers/iio/dac/ad5592r-base.c index 9234c6a09a93..095530c233e4 100644 --- a/drivers/iio/dac/ad5592r-base.c +++ b/drivers/iio/dac/ad5592r-base.c @@ -536,8 +536,9 @@ static int ad5592r_alloc_channels(struct ad5592r_state *st) st->channel_offstate[reg] = tmp; } - channels = devm_kzalloc(st->dev, - (1 + 2 * num_channels) * sizeof(*channels), GFP_KERNEL); + channels = devm_kcalloc(st->dev, + 1 + 2 * num_channels, sizeof(*channels), + GFP_KERNEL); if (!channels) return -ENOMEM; diff --git a/drivers/iio/imu/adis_buffer.c b/drivers/iio/imu/adis_buffer.c index 36607d52fee0..76643c5571aa 100644 --- a/drivers/iio/imu/adis_buffer.c +++ b/drivers/iio/imu/adis_buffer.c @@ -38,7 +38,7 @@ int adis_update_scan_mode(struct iio_dev *indio_dev, if (!adis->xfer) return -ENOMEM; - adis->buffer = kzalloc(indio_dev->scan_bytes * 2, GFP_KERNEL); + adis->buffer = kcalloc(indio_dev->scan_bytes, 2, GFP_KERNEL); if (!adis->buffer) return -ENOMEM; diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index ec98790e2a28..06ca3f7fcc44 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -436,7 +436,7 @@ struct iio_channel *iio_channel_get_all(struct device *dev) } /* NULL terminated array to save passing size */ - chans = kzalloc(sizeof(*chans)*(nummaps + 1), GFP_KERNEL); + chans = kcalloc(nummaps + 1, sizeof(*chans), GFP_KERNEL); if (chans == NULL) { ret = -ENOMEM; goto error_ret; diff --git a/drivers/iio/multiplexer/iio-mux.c b/drivers/iio/multiplexer/iio-mux.c index 60621ccd67e4..e1f44cecdef4 100644 --- a/drivers/iio/multiplexer/iio-mux.c +++ b/drivers/iio/multiplexer/iio-mux.c @@ -281,9 +281,10 @@ static int mux_configure_channel(struct device *dev, struct mux *mux, if (!page) return -ENOMEM; } - child->ext_info_cache = devm_kzalloc(dev, - sizeof(*child->ext_info_cache) * - num_ext_info, GFP_KERNEL); + child->ext_info_cache = devm_kcalloc(dev, + num_ext_info, + sizeof(*child->ext_info_cache), + GFP_KERNEL); if (!child->ext_info_cache) return -ENOMEM; diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c index 71a34bee453d..81d66f56e38f 100644 --- a/drivers/infiniband/core/cache.c +++ b/drivers/infiniband/core/cache.c @@ -1245,8 +1245,9 @@ int ib_cache_setup_one(struct ib_device *device) rwlock_init(&device->cache.lock); device->cache.ports = - kzalloc(sizeof(*device->cache.ports) * - (rdma_end_port(device) - rdma_start_port(device) + 1), GFP_KERNEL); + kcalloc(rdma_end_port(device) - rdma_start_port(device) + 1, + sizeof(*device->cache.ports), + GFP_KERNEL); if (!device->cache.ports) return -ENOMEM; diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 6813ee717a38..bff10ab141b0 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -1855,8 +1855,8 @@ static struct rdma_id_private *cma_new_conn_id(struct rdma_cm_id *listen_id, rt = &id->route; rt->num_paths = ib_event->param.req_rcvd.alternate_path ? 2 : 1; - rt->path_rec = kmalloc(sizeof *rt->path_rec * rt->num_paths, - GFP_KERNEL); + rt->path_rec = kmalloc_array(rt->num_paths, sizeof(*rt->path_rec), + GFP_KERNEL); if (!rt->path_rec) goto err; diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index 84f51386e1e3..6fa4c59dc7a7 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -336,8 +336,8 @@ static int read_port_immutable(struct ib_device *device) * Therefore port_immutable is declared as a 1 based array with * potential empty slots at the beginning. */ - device->port_immutable = kzalloc(sizeof(*device->port_immutable) - * (end_port + 1), + device->port_immutable = kcalloc(end_port + 1, + sizeof(*device->port_immutable), GFP_KERNEL); if (!device->port_immutable) return -ENOMEM; diff --git a/drivers/infiniband/core/fmr_pool.c b/drivers/infiniband/core/fmr_pool.c index a0a9ed719031..a077500f7f32 100644 --- a/drivers/infiniband/core/fmr_pool.c +++ b/drivers/infiniband/core/fmr_pool.c @@ -235,8 +235,9 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd, if (params->cache) { pool->cache_bucket = - kmalloc(IB_FMR_HASH_SIZE * sizeof *pool->cache_bucket, - GFP_KERNEL); + kmalloc_array(IB_FMR_HASH_SIZE, + sizeof(*pool->cache_bucket), + GFP_KERNEL); if (!pool->cache_bucket) { ret = -ENOMEM; goto out_free_pool; diff --git a/drivers/infiniband/core/iwpm_util.c b/drivers/infiniband/core/iwpm_util.c index da12da1c36f6..cdb63f3f4de7 100644 --- a/drivers/infiniband/core/iwpm_util.c +++ b/drivers/infiniband/core/iwpm_util.c @@ -56,14 +56,16 @@ int iwpm_init(u8 nl_client) int ret = 0; mutex_lock(&iwpm_admin_lock); if (atomic_read(&iwpm_admin.refcount) == 0) { - iwpm_hash_bucket = kzalloc(IWPM_MAPINFO_HASH_SIZE * - sizeof(struct hlist_head), GFP_KERNEL); + iwpm_hash_bucket = kcalloc(IWPM_MAPINFO_HASH_SIZE, + sizeof(struct hlist_head), + GFP_KERNEL); if (!iwpm_hash_bucket) { ret = -ENOMEM; goto init_exit; } - iwpm_reminfo_bucket = kzalloc(IWPM_REMINFO_HASH_SIZE * - sizeof(struct hlist_head), GFP_KERNEL); + iwpm_reminfo_bucket = kcalloc(IWPM_REMINFO_HASH_SIZE, + sizeof(struct hlist_head), + GFP_KERNEL); if (!iwpm_reminfo_bucket) { kfree(iwpm_hash_bucket); ret = -ENOMEM; diff --git a/drivers/infiniband/core/umem_odp.c b/drivers/infiniband/core/umem_odp.c index 2aadf5813a40..182436b92ba9 100644 --- a/drivers/infiniband/core/umem_odp.c +++ b/drivers/infiniband/core/umem_odp.c @@ -285,13 +285,15 @@ struct ib_umem *ib_alloc_odp_umem(struct ib_ucontext *context, mutex_init(&odp_data->umem_mutex); init_completion(&odp_data->notifier_completion); - odp_data->page_list = vzalloc(pages * sizeof(*odp_data->page_list)); + odp_data->page_list = + vzalloc(array_size(pages, sizeof(*odp_data->page_list))); if (!odp_data->page_list) { ret = -ENOMEM; goto out_odp_data; } - odp_data->dma_list = vzalloc(pages * sizeof(*odp_data->dma_list)); + odp_data->dma_list = + vzalloc(array_size(pages, sizeof(*odp_data->dma_list))); if (!odp_data->dma_list) { ret = -ENOMEM; goto out_page_list; @@ -371,15 +373,17 @@ int ib_umem_odp_get(struct ib_ucontext *context, struct ib_umem *umem, init_completion(&umem->odp_data->notifier_completion); if (ib_umem_num_pages(umem)) { - umem->odp_data->page_list = vzalloc(ib_umem_num_pages(umem) * - sizeof(*umem->odp_data->page_list)); + umem->odp_data->page_list = + vzalloc(array_size(sizeof(*umem->odp_data->page_list), + ib_umem_num_pages(umem))); if (!umem->odp_data->page_list) { ret_val = -ENOMEM; goto out_odp_data; } - umem->odp_data->dma_list = vzalloc(ib_umem_num_pages(umem) * - sizeof(*umem->odp_data->dma_list)); + umem->odp_data->dma_list = + vzalloc(array_size(sizeof(*umem->odp_data->dma_list), + ib_umem_num_pages(umem))); if (!umem->odp_data->dma_list) { ret_val = -ENOMEM; goto out_page_list; diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 3179a95c6f5e..3e90b6a1d9d2 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -3559,8 +3559,8 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file, goto err_uobj; } - flow_attr = kzalloc(sizeof(*flow_attr) + cmd.flow_attr.num_of_specs * - sizeof(union ib_flow_spec), GFP_KERNEL); + flow_attr = kzalloc(struct_size(flow_attr, flows, + cmd.flow_attr.num_of_specs), GFP_KERNEL); if (!flow_attr) { err = -ENOMEM; goto err_put; diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c index 3328acc53c2a..dcb4bba522ba 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_hal.c +++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c @@ -279,7 +279,7 @@ int cxio_create_qp(struct cxio_rdev *rdev_p, u32 kernel_domain, if (!wq->qpid) return -ENOMEM; - wq->rq = kzalloc(depth * sizeof(struct t3_swrq), GFP_KERNEL); + wq->rq = kcalloc(depth, sizeof(struct t3_swrq), GFP_KERNEL); if (!wq->rq) goto err1; @@ -287,7 +287,7 @@ int cxio_create_qp(struct cxio_rdev *rdev_p, u32 kernel_domain, if (!wq->rq_addr) goto err2; - wq->sq = kzalloc(depth * sizeof(struct t3_swsq), GFP_KERNEL); + wq->sq = kcalloc(depth, sizeof(struct t3_swsq), GFP_KERNEL); if (!wq->sq) goto err3; diff --git a/drivers/infiniband/hw/cxgb4/device.c b/drivers/infiniband/hw/cxgb4/device.c index 44161ca4d2a8..a3c3418afd73 100644 --- a/drivers/infiniband/hw/cxgb4/device.c +++ b/drivers/infiniband/hw/cxgb4/device.c @@ -859,8 +859,9 @@ static int c4iw_rdev_open(struct c4iw_rdev *rdev) rdev->status_page->cq_size = rdev->lldi.vr->cq.size; if (c4iw_wr_log) { - rdev->wr_log = kzalloc((1 << c4iw_wr_log_size_order) * - sizeof(*rdev->wr_log), GFP_KERNEL); + rdev->wr_log = kcalloc(1 << c4iw_wr_log_size_order, + sizeof(*rdev->wr_log), + GFP_KERNEL); if (rdev->wr_log) { rdev->wr_log_size = 1 << c4iw_wr_log_size_order; atomic_set(&rdev->wr_log_idx, 0); @@ -1445,7 +1446,7 @@ static void recover_queues(struct uld_ctx *ctx) ctx->dev->db_state = RECOVERY; idr_for_each(&ctx->dev->qpidr, count_qps, &count); - qp_list.qps = kzalloc(count * sizeof *qp_list.qps, GFP_ATOMIC); + qp_list.qps = kcalloc(count, sizeof(*qp_list.qps), GFP_ATOMIC); if (!qp_list.qps) { spin_unlock_irq(&ctx->dev->lock); return; diff --git a/drivers/infiniband/hw/cxgb4/id_table.c b/drivers/infiniband/hw/cxgb4/id_table.c index 5c2cfdea06ad..724d23297b35 100644 --- a/drivers/infiniband/hw/cxgb4/id_table.c +++ b/drivers/infiniband/hw/cxgb4/id_table.c @@ -92,8 +92,8 @@ int c4iw_id_table_alloc(struct c4iw_id_table *alloc, u32 start, u32 num, alloc->last = 0; alloc->max = num; spin_lock_init(&alloc->lock); - alloc->table = kmalloc(BITS_TO_LONGS(num) * sizeof(long), - GFP_KERNEL); + alloc->table = kmalloc_array(BITS_TO_LONGS(num), sizeof(long), + GFP_KERNEL); if (!alloc->table) return -ENOMEM; diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index 4106eed1b8fb..aef53305f1c3 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -216,15 +216,15 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq, } if (!user) { - wq->sq.sw_sq = kzalloc(wq->sq.size * sizeof *wq->sq.sw_sq, - GFP_KERNEL); + wq->sq.sw_sq = kcalloc(wq->sq.size, sizeof(*wq->sq.sw_sq), + GFP_KERNEL); if (!wq->sq.sw_sq) { ret = -ENOMEM; goto free_rq_qid; } - wq->rq.sw_rq = kzalloc(wq->rq.size * sizeof *wq->rq.sw_rq, - GFP_KERNEL); + wq->rq.sw_rq = kcalloc(wq->rq.size, sizeof(*wq->rq.sw_rq), + GFP_KERNEL); if (!wq->rq.sw_rq) { ret = -ENOMEM; goto free_sw_sq; diff --git a/drivers/infiniband/hw/hfi1/sdma.c b/drivers/infiniband/hw/hfi1/sdma.c index 298e0e3fc0c9..7fb350b87b49 100644 --- a/drivers/infiniband/hw/hfi1/sdma.c +++ b/drivers/infiniband/hw/hfi1/sdma.c @@ -1461,7 +1461,8 @@ int sdma_init(struct hfi1_devdata *dd, u8 port) if (!sde->descq) goto bail; sde->tx_ring = - kvzalloc_node(sizeof(struct sdma_txreq *) * descq_cnt, + kvzalloc_node(array_size(descq_cnt, + sizeof(struct sdma_txreq *)), GFP_KERNEL, dd->node); if (!sde->tx_ring) goto bail; diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index 0e8dad68910a..a6e11be0ea0f 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -3177,7 +3177,7 @@ static int hns_roce_v2_modify_qp(struct ib_qp *ibqp, struct device *dev = hr_dev->dev; int ret = -EINVAL; - context = kzalloc(2 * sizeof(*context), GFP_KERNEL); + context = kcalloc(2, sizeof(*context), GFP_KERNEL); if (!context) return -ENOMEM; diff --git a/drivers/infiniband/hw/hns/hns_roce_mr.c b/drivers/infiniband/hw/hns/hns_roce_mr.c index d1fe0e7957e3..eb26a5f6fc58 100644 --- a/drivers/infiniband/hw/hns/hns_roce_mr.c +++ b/drivers/infiniband/hw/hns/hns_roce_mr.c @@ -144,7 +144,7 @@ static int hns_roce_buddy_init(struct hns_roce_buddy *buddy, int max_order) buddy->bits[i] = kcalloc(s, sizeof(long), GFP_KERNEL | __GFP_NOWARN); if (!buddy->bits[i]) { - buddy->bits[i] = vzalloc(s * sizeof(long)); + buddy->bits[i] = vzalloc(array_size(s, sizeof(long))); if (!buddy->bits[i]) goto err_out_free; } diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c index d604b3d5aa3e..90a3e2642c2e 100644 --- a/drivers/infiniband/hw/mlx4/mad.c +++ b/drivers/infiniband/hw/mlx4/mad.c @@ -1613,7 +1613,8 @@ static int mlx4_ib_alloc_pv_bufs(struct mlx4_ib_demux_pv_ctx *ctx, tun_qp = &ctx->qp[qp_type]; - tun_qp->ring = kzalloc(sizeof (struct mlx4_ib_buf) * MLX4_NUM_TUNNEL_BUFS, + tun_qp->ring = kcalloc(MLX4_NUM_TUNNEL_BUFS, + sizeof(struct mlx4_ib_buf), GFP_KERNEL); if (!tun_qp->ring) return -ENOMEM; diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index f839bf3b1497..4ec519afc45b 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -302,7 +302,8 @@ static int mlx4_ib_add_gid(const union ib_gid *gid, ctx->refcount++; } if (!ret && hw_update) { - gids = kmalloc(sizeof(*gids) * MLX4_MAX_PORT_GIDS, GFP_ATOMIC); + gids = kmalloc_array(MLX4_MAX_PORT_GIDS, sizeof(*gids), + GFP_ATOMIC); if (!gids) { ret = -ENOMEM; } else { @@ -355,7 +356,8 @@ static int mlx4_ib_del_gid(const struct ib_gid_attr *attr, void **context) if (!ret && hw_update) { int i; - gids = kmalloc(sizeof(*gids) * MLX4_MAX_PORT_GIDS, GFP_ATOMIC); + gids = kmalloc_array(MLX4_MAX_PORT_GIDS, sizeof(*gids), + GFP_ATOMIC); if (!gids) { ret = -ENOMEM; } else { @@ -2872,9 +2874,9 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) goto err_counter; ibdev->ib_uc_qpns_bitmap = - kmalloc(BITS_TO_LONGS(ibdev->steer_qpn_count) * - sizeof(long), - GFP_KERNEL); + kmalloc_array(BITS_TO_LONGS(ibdev->steer_qpn_count), + sizeof(long), + GFP_KERNEL); if (!ibdev->ib_uc_qpns_bitmap) goto err_steer_qp_release; diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index cd2c08c45334..3b8045fd23ed 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -573,8 +573,8 @@ static int alloc_proxy_bufs(struct ib_device *dev, struct mlx4_ib_qp *qp) int i; qp->sqp_proxy_rcv = - kmalloc(sizeof (struct mlx4_ib_buf) * qp->rq.wqe_cnt, - GFP_KERNEL); + kmalloc_array(qp->rq.wqe_cnt, sizeof(struct mlx4_ib_buf), + GFP_KERNEL); if (!qp->sqp_proxy_rcv) return -ENOMEM; for (i = 0; i < qp->rq.wqe_cnt; i++) { diff --git a/drivers/infiniband/hw/mlx5/srq.c b/drivers/infiniband/hw/mlx5/srq.c index 3c7522d025f2..0af7b7905550 100644 --- a/drivers/infiniband/hw/mlx5/srq.c +++ b/drivers/infiniband/hw/mlx5/srq.c @@ -127,7 +127,7 @@ static int create_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq, goto err_umem; } - in->pas = kvzalloc(sizeof(*in->pas) * ncont, GFP_KERNEL); + in->pas = kvcalloc(ncont, sizeof(*in->pas), GFP_KERNEL); if (!in->pas) { err = -ENOMEM; goto err_umem; @@ -189,7 +189,7 @@ static int create_srq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_srq *srq, } mlx5_ib_dbg(dev, "srq->buf.page_shift = %d\n", srq->buf.page_shift); - in->pas = kvzalloc(sizeof(*in->pas) * srq->buf.npages, GFP_KERNEL); + in->pas = kvcalloc(srq->buf.npages, sizeof(*in->pas), GFP_KERNEL); if (!in->pas) { err = -ENOMEM; goto err_buf; diff --git a/drivers/infiniband/hw/mthca/mthca_allocator.c b/drivers/infiniband/hw/mthca/mthca_allocator.c index b4e0cf4e95cd..aaf10dd5364d 100644 --- a/drivers/infiniband/hw/mthca/mthca_allocator.c +++ b/drivers/infiniband/hw/mthca/mthca_allocator.c @@ -90,8 +90,8 @@ int mthca_alloc_init(struct mthca_alloc *alloc, u32 num, u32 mask, alloc->max = num; alloc->mask = mask; spin_lock_init(&alloc->lock); - alloc->table = kmalloc(BITS_TO_LONGS(num) * sizeof (long), - GFP_KERNEL); + alloc->table = kmalloc_array(BITS_TO_LONGS(num), sizeof(long), + GFP_KERNEL); if (!alloc->table) return -ENOMEM; @@ -162,7 +162,8 @@ int mthca_array_init(struct mthca_array *array, int nent) int npage = (nent * sizeof (void *) + PAGE_SIZE - 1) / PAGE_SIZE; int i; - array->page_list = kmalloc(npage * sizeof *array->page_list, GFP_KERNEL); + array->page_list = kmalloc_array(npage, sizeof(*array->page_list), + GFP_KERNEL); if (!array->page_list) return -ENOMEM; @@ -220,7 +221,8 @@ int mthca_buf_alloc(struct mthca_dev *dev, int size, int max_direct, npages *= 2; } - dma_list = kmalloc(npages * sizeof *dma_list, GFP_KERNEL); + dma_list = kmalloc_array(npages, sizeof(*dma_list), + GFP_KERNEL); if (!dma_list) goto err_free; @@ -231,12 +233,14 @@ int mthca_buf_alloc(struct mthca_dev *dev, int size, int max_direct, npages = (size + PAGE_SIZE - 1) / PAGE_SIZE; shift = PAGE_SHIFT; - dma_list = kmalloc(npages * sizeof *dma_list, GFP_KERNEL); + dma_list = kmalloc_array(npages, sizeof(*dma_list), + GFP_KERNEL); if (!dma_list) return -ENOMEM; - buf->page_list = kmalloc(npages * sizeof *buf->page_list, - GFP_KERNEL); + buf->page_list = kmalloc_array(npages, + sizeof(*buf->page_list), + GFP_KERNEL); if (!buf->page_list) goto err_out; diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c index 419a2a20c047..83aa47eb81a9 100644 --- a/drivers/infiniband/hw/mthca/mthca_cmd.c +++ b/drivers/infiniband/hw/mthca/mthca_cmd.c @@ -565,9 +565,9 @@ int mthca_cmd_use_events(struct mthca_dev *dev) { int i; - dev->cmd.context = kmalloc(dev->cmd.max_cmds * - sizeof (struct mthca_cmd_context), - GFP_KERNEL); + dev->cmd.context = kmalloc_array(dev->cmd.max_cmds, + sizeof(struct mthca_cmd_context), + GFP_KERNEL); if (!dev->cmd.context) return -ENOMEM; diff --git a/drivers/infiniband/hw/mthca/mthca_eq.c b/drivers/infiniband/hw/mthca/mthca_eq.c index 690201738993..30400ea4808b 100644 --- a/drivers/infiniband/hw/mthca/mthca_eq.c +++ b/drivers/infiniband/hw/mthca/mthca_eq.c @@ -479,15 +479,15 @@ static int mthca_create_eq(struct mthca_dev *dev, eq->nent = roundup_pow_of_two(max(nent, 2)); npages = ALIGN(eq->nent * MTHCA_EQ_ENTRY_SIZE, PAGE_SIZE) / PAGE_SIZE; - eq->page_list = kmalloc(npages * sizeof *eq->page_list, - GFP_KERNEL); + eq->page_list = kmalloc_array(npages, sizeof(*eq->page_list), + GFP_KERNEL); if (!eq->page_list) goto err_out; for (i = 0; i < npages; ++i) eq->page_list[i].buf = NULL; - dma_list = kmalloc(npages * sizeof *dma_list, GFP_KERNEL); + dma_list = kmalloc_array(npages, sizeof(*dma_list), GFP_KERNEL); if (!dma_list) goto err_out_free; diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c index 7a31be3c3e73..cc9c0c8ccba3 100644 --- a/drivers/infiniband/hw/mthca/mthca_memfree.c +++ b/drivers/infiniband/hw/mthca/mthca_memfree.c @@ -712,9 +712,9 @@ int mthca_init_db_tab(struct mthca_dev *dev) dev->db_tab->max_group1 = 0; dev->db_tab->min_group2 = dev->db_tab->npages - 1; - dev->db_tab->page = kmalloc(dev->db_tab->npages * - sizeof *dev->db_tab->page, - GFP_KERNEL); + dev->db_tab->page = kmalloc_array(dev->db_tab->npages, + sizeof(*dev->db_tab->page), + GFP_KERNEL); if (!dev->db_tab->page) { kfree(dev->db_tab); return -ENOMEM; diff --git a/drivers/infiniband/hw/mthca/mthca_mr.c b/drivers/infiniband/hw/mthca/mthca_mr.c index ed9a989e501b..6686042aafb4 100644 --- a/drivers/infiniband/hw/mthca/mthca_mr.c +++ b/drivers/infiniband/hw/mthca/mthca_mr.c @@ -144,7 +144,7 @@ static int mthca_buddy_init(struct mthca_buddy *buddy, int max_order) buddy->max_order = max_order; spin_lock_init(&buddy->lock); - buddy->bits = kzalloc((buddy->max_order + 1) * sizeof (long *), + buddy->bits = kcalloc(buddy->max_order + 1, sizeof(long *), GFP_KERNEL); buddy->num_free = kcalloc((buddy->max_order + 1), sizeof *buddy->num_free, GFP_KERNEL); @@ -153,7 +153,7 @@ static int mthca_buddy_init(struct mthca_buddy *buddy, int max_order) for (i = 0; i <= buddy->max_order; ++i) { s = BITS_TO_LONGS(1 << (buddy->max_order - i)); - buddy->bits[i] = kmalloc(s * sizeof (long), GFP_KERNEL); + buddy->bits[i] = kmalloc_array(s, sizeof(long), GFP_KERNEL); if (!buddy->bits[i]) goto err_out_free; bitmap_zero(buddy->bits[i], diff --git a/drivers/infiniband/hw/mthca/mthca_profile.c b/drivers/infiniband/hw/mthca/mthca_profile.c index 15d064479ef6..7ea970774839 100644 --- a/drivers/infiniband/hw/mthca/mthca_profile.c +++ b/drivers/infiniband/hw/mthca/mthca_profile.c @@ -79,7 +79,7 @@ s64 mthca_make_profile(struct mthca_dev *dev, struct mthca_resource *profile; int i, j; - profile = kzalloc(MTHCA_RES_NUM * sizeof *profile, GFP_KERNEL); + profile = kcalloc(MTHCA_RES_NUM, sizeof(*profile), GFP_KERNEL); if (!profile) return -ENOMEM; diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index d21960cd9a49..af1c49d70b89 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c @@ -1054,8 +1054,8 @@ static int mthca_alloc_wqe_buf(struct mthca_dev *dev, size = PAGE_ALIGN(qp->send_wqe_offset + (qp->sq.max << qp->sq.wqe_shift)); - qp->wrid = kmalloc((qp->rq.max + qp->sq.max) * sizeof (u64), - GFP_KERNEL); + qp->wrid = kmalloc_array(qp->rq.max + qp->sq.max, sizeof(u64), + GFP_KERNEL); if (!qp->wrid) goto err_out; diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c index d22f970480c0..f79732bc73b4 100644 --- a/drivers/infiniband/hw/mthca/mthca_srq.c +++ b/drivers/infiniband/hw/mthca/mthca_srq.c @@ -155,7 +155,7 @@ static int mthca_alloc_srq_buf(struct mthca_dev *dev, struct mthca_pd *pd, if (pd->ibpd.uobject) return 0; - srq->wrid = kmalloc(srq->max * sizeof (u64), GFP_KERNEL); + srq->wrid = kmalloc_array(srq->max, sizeof(u64), GFP_KERNEL); if (!srq->wrid) return -ENOMEM; diff --git a/drivers/infiniband/hw/nes/nes_mgt.c b/drivers/infiniband/hw/nes/nes_mgt.c index 21e0ebd39a05..9bdb84dc225c 100644 --- a/drivers/infiniband/hw/nes/nes_mgt.c +++ b/drivers/infiniband/hw/nes/nes_mgt.c @@ -878,7 +878,8 @@ int nes_init_mgt_qp(struct nes_device *nesdev, struct net_device *netdev, struct int ret; /* Allocate space the all mgt QPs once */ - mgtvnic = kzalloc(NES_MGT_QP_COUNT * sizeof(struct nes_vnic_mgt), GFP_KERNEL); + mgtvnic = kcalloc(NES_MGT_QP_COUNT, sizeof(struct nes_vnic_mgt), + GFP_KERNEL); if (!mgtvnic) return -ENOMEM; diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c index 007d5e8a0121..61014e251555 100644 --- a/drivers/infiniband/hw/nes/nes_nic.c +++ b/drivers/infiniband/hw/nes/nes_nic.c @@ -904,7 +904,7 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev) int i; struct netdev_hw_addr *ha; - addrs = kmalloc(ETH_ALEN * mc_count, GFP_ATOMIC); + addrs = kmalloc_array(mc_count, ETH_ALEN, GFP_ATOMIC); if (!addrs) { set_allmulti(nesdev, nic_active_bit); goto unlock; diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index 1040a6e34230..32f26556c808 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -2254,8 +2254,9 @@ static struct ib_mr *nes_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, ibmr = ERR_PTR(-ENOMEM); goto reg_user_mr_err; } - root_vpbl.leaf_vpbl = kzalloc(sizeof(*root_vpbl.leaf_vpbl)*1024, - GFP_KERNEL); + root_vpbl.leaf_vpbl = kcalloc(1024, + sizeof(*root_vpbl.leaf_vpbl), + GFP_KERNEL); if (!root_vpbl.leaf_vpbl) { ib_umem_release(region); pci_free_consistent(nesdev->pcidev, 8192, root_vpbl.pbl_vbase, diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c index 2c260e1c29d1..6c136e5017fe 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c @@ -3096,7 +3096,7 @@ static int ocrdma_create_eqs(struct ocrdma_dev *dev) if (!num_eq) return -EINVAL; - dev->eq_tbl = kzalloc(sizeof(struct ocrdma_eq) * num_eq, GFP_KERNEL); + dev->eq_tbl = kcalloc(num_eq, sizeof(struct ocrdma_eq), GFP_KERNEL); if (!dev->eq_tbl) return -ENOMEM; diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_main.c b/drivers/infiniband/hw/ocrdma/ocrdma_main.c index eb8b6a935016..5962c0ed9847 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_main.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_main.c @@ -221,19 +221,20 @@ static int ocrdma_register_device(struct ocrdma_dev *dev) static int ocrdma_alloc_resources(struct ocrdma_dev *dev) { mutex_init(&dev->dev_lock); - dev->cq_tbl = kzalloc(sizeof(struct ocrdma_cq *) * - OCRDMA_MAX_CQ, GFP_KERNEL); + dev->cq_tbl = kcalloc(OCRDMA_MAX_CQ, sizeof(struct ocrdma_cq *), + GFP_KERNEL); if (!dev->cq_tbl) goto alloc_err; if (dev->attr.max_qp) { - dev->qp_tbl = kzalloc(sizeof(struct ocrdma_qp *) * - OCRDMA_MAX_QP, GFP_KERNEL); + dev->qp_tbl = kcalloc(OCRDMA_MAX_QP, + sizeof(struct ocrdma_qp *), + GFP_KERNEL); if (!dev->qp_tbl) goto alloc_err; } - dev->stag_arr = kzalloc(sizeof(u64) * OCRDMA_MAX_STAG, GFP_KERNEL); + dev->stag_arr = kcalloc(OCRDMA_MAX_STAG, sizeof(u64), GFP_KERNEL); if (dev->stag_arr == NULL) goto alloc_err; diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c index 784ed6b09a46..82e20fc32890 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c @@ -843,8 +843,8 @@ static int ocrdma_build_pbl_tbl(struct ocrdma_dev *dev, struct ocrdma_hw_mr *mr) void *va; dma_addr_t pa; - mr->pbl_table = kzalloc(sizeof(struct ocrdma_pbl) * - mr->num_pbls, GFP_KERNEL); + mr->pbl_table = kcalloc(mr->num_pbls, sizeof(struct ocrdma_pbl), + GFP_KERNEL); if (!mr->pbl_table) return -ENOMEM; @@ -1323,12 +1323,12 @@ static void ocrdma_set_qp_db(struct ocrdma_dev *dev, struct ocrdma_qp *qp, static int ocrdma_alloc_wr_id_tbl(struct ocrdma_qp *qp) { qp->wqe_wr_id_tbl = - kzalloc(sizeof(*(qp->wqe_wr_id_tbl)) * qp->sq.max_cnt, + kcalloc(qp->sq.max_cnt, sizeof(*(qp->wqe_wr_id_tbl)), GFP_KERNEL); if (qp->wqe_wr_id_tbl == NULL) return -ENOMEM; qp->rqe_wr_id_tbl = - kzalloc(sizeof(u64) * qp->rq.max_cnt, GFP_KERNEL); + kcalloc(qp->rq.max_cnt, sizeof(u64), GFP_KERNEL); if (qp->rqe_wr_id_tbl == NULL) return -ENOMEM; @@ -1865,15 +1865,16 @@ struct ib_srq *ocrdma_create_srq(struct ib_pd *ibpd, if (udata == NULL) { status = -ENOMEM; - srq->rqe_wr_id_tbl = kzalloc(sizeof(u64) * srq->rq.max_cnt, - GFP_KERNEL); + srq->rqe_wr_id_tbl = kcalloc(srq->rq.max_cnt, sizeof(u64), + GFP_KERNEL); if (srq->rqe_wr_id_tbl == NULL) goto arm_err; srq->bit_fields_len = (srq->rq.max_cnt / 32) + (srq->rq.max_cnt % 32 ? 1 : 0); srq->idx_bit_fields = - kmalloc(srq->bit_fields_len * sizeof(u32), GFP_KERNEL); + kmalloc_array(srq->bit_fields_len, sizeof(u32), + GFP_KERNEL); if (srq->idx_bit_fields == NULL) goto arm_err; memset(srq->idx_bit_fields, 0xff, diff --git a/drivers/infiniband/hw/qedr/main.c b/drivers/infiniband/hw/qedr/main.c index f4cb60b658ea..ad22b32bbd9c 100644 --- a/drivers/infiniband/hw/qedr/main.c +++ b/drivers/infiniband/hw/qedr/main.c @@ -317,8 +317,8 @@ static int qedr_alloc_resources(struct qedr_dev *dev) u16 n_entries; int i, rc; - dev->sgid_tbl = kzalloc(sizeof(union ib_gid) * - QEDR_MAX_SGID, GFP_KERNEL); + dev->sgid_tbl = kcalloc(QEDR_MAX_SGID, sizeof(union ib_gid), + GFP_KERNEL); if (!dev->sgid_tbl) return -ENOMEM; diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index 710032f1fad7..f7ac8fc9b531 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -1614,7 +1614,7 @@ static int qedr_create_kernel_qp(struct qedr_dev *dev, qp->sq.max_wr = min_t(u32, attrs->cap.max_send_wr * dev->wq_multiplier, dev->attr.max_sqe); - qp->wqe_wr_id = kzalloc(qp->sq.max_wr * sizeof(*qp->wqe_wr_id), + qp->wqe_wr_id = kcalloc(qp->sq.max_wr, sizeof(*qp->wqe_wr_id), GFP_KERNEL); if (!qp->wqe_wr_id) { DP_ERR(dev, "create qp: failed SQ shadow memory allocation\n"); @@ -1632,7 +1632,7 @@ static int qedr_create_kernel_qp(struct qedr_dev *dev, qp->rq.max_wr = (u16) max_t(u32, attrs->cap.max_recv_wr, 1); /* Allocate driver internal RQ array */ - qp->rqe_wr_id = kzalloc(qp->rq.max_wr * sizeof(*qp->rqe_wr_id), + qp->rqe_wr_id = kcalloc(qp->rq.max_wr, sizeof(*qp->rqe_wr_id), GFP_KERNEL); if (!qp->rqe_wr_id) { DP_ERR(dev, diff --git a/drivers/infiniband/hw/qib/qib_iba6120.c b/drivers/infiniband/hw/qib/qib_iba6120.c index 8a15e5c7dd91..fb1ff59f40bd 100644 --- a/drivers/infiniband/hw/qib/qib_iba6120.c +++ b/drivers/infiniband/hw/qib/qib_iba6120.c @@ -2496,15 +2496,16 @@ static void init_6120_cntrnames(struct qib_devdata *dd) dd->cspec->cntrnamelen = sizeof(cntr6120names) - 1; else dd->cspec->cntrnamelen = 1 + s - cntr6120names; - dd->cspec->cntrs = kmalloc(dd->cspec->ncntrs - * sizeof(u64), GFP_KERNEL); + dd->cspec->cntrs = kmalloc_array(dd->cspec->ncntrs, sizeof(u64), + GFP_KERNEL); for (i = 0, s = (char *)portcntr6120names; s; i++) s = strchr(s + 1, '\n'); dd->cspec->nportcntrs = i - 1; dd->cspec->portcntrnamelen = sizeof(portcntr6120names) - 1; - dd->cspec->portcntrs = kmalloc(dd->cspec->nportcntrs - * sizeof(u64), GFP_KERNEL); + dd->cspec->portcntrs = kmalloc_array(dd->cspec->nportcntrs, + sizeof(u64), + GFP_KERNEL); } static u32 qib_read_6120cntrs(struct qib_devdata *dd, loff_t pos, char **namep, diff --git a/drivers/infiniband/hw/qib/qib_iba7220.c b/drivers/infiniband/hw/qib/qib_iba7220.c index bdff2326731e..163a57a88742 100644 --- a/drivers/infiniband/hw/qib/qib_iba7220.c +++ b/drivers/infiniband/hw/qib/qib_iba7220.c @@ -3147,15 +3147,16 @@ static void init_7220_cntrnames(struct qib_devdata *dd) dd->cspec->cntrnamelen = sizeof(cntr7220names) - 1; else dd->cspec->cntrnamelen = 1 + s - cntr7220names; - dd->cspec->cntrs = kmalloc(dd->cspec->ncntrs - * sizeof(u64), GFP_KERNEL); + dd->cspec->cntrs = kmalloc_array(dd->cspec->ncntrs, sizeof(u64), + GFP_KERNEL); for (i = 0, s = (char *)portcntr7220names; s; i++) s = strchr(s + 1, '\n'); dd->cspec->nportcntrs = i - 1; dd->cspec->portcntrnamelen = sizeof(portcntr7220names) - 1; - dd->cspec->portcntrs = kmalloc(dd->cspec->nportcntrs - * sizeof(u64), GFP_KERNEL); + dd->cspec->portcntrs = kmalloc_array(dd->cspec->nportcntrs, + sizeof(u64), + GFP_KERNEL); } static u32 qib_read_7220cntrs(struct qib_devdata *dd, loff_t pos, char **namep, diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c index 8414ae44a518..bf5e222eed8e 100644 --- a/drivers/infiniband/hw/qib/qib_iba7322.c +++ b/drivers/infiniband/hw/qib/qib_iba7322.c @@ -3648,8 +3648,9 @@ static int qib_do_7322_reset(struct qib_devdata *dd) if (msix_entries) { /* can be up to 512 bytes, too big for stack */ - msix_vecsave = kmalloc(2 * dd->cspec->num_msix_entries * - sizeof(u64), GFP_KERNEL); + msix_vecsave = kmalloc_array(2 * dd->cspec->num_msix_entries, + sizeof(u64), + GFP_KERNEL); } /* @@ -5009,16 +5010,17 @@ static void init_7322_cntrnames(struct qib_devdata *dd) dd->cspec->cntrnamelen = sizeof(cntr7322names) - 1; else dd->cspec->cntrnamelen = 1 + s - cntr7322names; - dd->cspec->cntrs = kmalloc(dd->cspec->ncntrs - * sizeof(u64), GFP_KERNEL); + dd->cspec->cntrs = kmalloc_array(dd->cspec->ncntrs, sizeof(u64), + GFP_KERNEL); for (i = 0, s = (char *)portcntr7322names; s; i++) s = strchr(s + 1, '\n'); dd->cspec->nportcntrs = i - 1; dd->cspec->portcntrnamelen = sizeof(portcntr7322names) - 1; for (i = 0; i < dd->num_pports; ++i) { - dd->pport[i].cpspec->portcntrs = kmalloc(dd->cspec->nportcntrs - * sizeof(u64), GFP_KERNEL); + dd->pport[i].cpspec->portcntrs = + kmalloc_array(dd->cspec->nportcntrs, sizeof(u64), + GFP_KERNEL); } } @@ -6412,12 +6414,15 @@ static int qib_init_7322_variables(struct qib_devdata *dd) sbufcnt = dd->piobcnt2k + dd->piobcnt4k + NUM_VL15_BUFS + BITS_PER_LONG - 1; sbufcnt /= BITS_PER_LONG; - dd->cspec->sendchkenable = kmalloc(sbufcnt * - sizeof(*dd->cspec->sendchkenable), GFP_KERNEL); - dd->cspec->sendgrhchk = kmalloc(sbufcnt * - sizeof(*dd->cspec->sendgrhchk), GFP_KERNEL); - dd->cspec->sendibchk = kmalloc(sbufcnt * - sizeof(*dd->cspec->sendibchk), GFP_KERNEL); + dd->cspec->sendchkenable = + kmalloc_array(sbufcnt, sizeof(*dd->cspec->sendchkenable), + GFP_KERNEL); + dd->cspec->sendgrhchk = + kmalloc_array(sbufcnt, sizeof(*dd->cspec->sendgrhchk), + GFP_KERNEL); + dd->cspec->sendibchk = + kmalloc_array(sbufcnt, sizeof(*dd->cspec->sendibchk), + GFP_KERNEL); if (!dd->cspec->sendchkenable || !dd->cspec->sendgrhchk || !dd->cspec->sendibchk) { ret = -ENOMEM; @@ -7290,8 +7295,9 @@ struct qib_devdata *qib_init_iba7322_funcs(struct pci_dev *pdev, actual_cnt -= dd->num_pports; tabsize = actual_cnt; - dd->cspec->msix_entries = kzalloc(tabsize * - sizeof(struct qib_msix_entry), GFP_KERNEL); + dd->cspec->msix_entries = kcalloc(tabsize, + sizeof(struct qib_msix_entry), + GFP_KERNEL); if (!dd->cspec->msix_entries) tabsize = 0; diff --git a/drivers/infiniband/hw/qib/qib_init.c b/drivers/infiniband/hw/qib/qib_init.c index 015520289735..d7cdc77d6306 100644 --- a/drivers/infiniband/hw/qib/qib_init.c +++ b/drivers/infiniband/hw/qib/qib_init.c @@ -369,11 +369,13 @@ static void init_shadow_tids(struct qib_devdata *dd) struct page **pages; dma_addr_t *addrs; - pages = vzalloc(dd->cfgctxts * dd->rcvtidcnt * sizeof(struct page *)); + pages = vzalloc(array_size(sizeof(struct page *), + dd->cfgctxts * dd->rcvtidcnt)); if (!pages) goto bail; - addrs = vzalloc(dd->cfgctxts * dd->rcvtidcnt * sizeof(dma_addr_t)); + addrs = vzalloc(array_size(sizeof(dma_addr_t), + dd->cfgctxts * dd->rcvtidcnt)); if (!addrs) goto bail_free; @@ -1134,8 +1136,8 @@ struct qib_devdata *qib_alloc_devdata(struct pci_dev *pdev, size_t extra) if (!qib_cpulist_count) { u32 count = num_online_cpus(); - qib_cpulist = kzalloc(BITS_TO_LONGS(count) * - sizeof(long), GFP_KERNEL); + qib_cpulist = kcalloc(BITS_TO_LONGS(count), sizeof(long), + GFP_KERNEL); if (qib_cpulist) qib_cpulist_count = count; } @@ -1673,8 +1675,8 @@ int qib_setup_eagerbufs(struct qib_ctxtdata *rcd) size = rcd->rcvegrbuf_size; if (!rcd->rcvegrbuf) { rcd->rcvegrbuf = - kzalloc_node(chunk * sizeof(rcd->rcvegrbuf[0]), - GFP_KERNEL, rcd->node_id); + kcalloc_node(chunk, sizeof(rcd->rcvegrbuf[0]), + GFP_KERNEL, rcd->node_id); if (!rcd->rcvegrbuf) goto bail; } diff --git a/drivers/infiniband/hw/usnic/usnic_ib_qp_grp.c b/drivers/infiniband/hw/usnic/usnic_ib_qp_grp.c index 912d8ef04352..bf5136533d49 100644 --- a/drivers/infiniband/hw/usnic/usnic_ib_qp_grp.c +++ b/drivers/infiniband/hw/usnic/usnic_ib_qp_grp.c @@ -543,7 +543,7 @@ alloc_res_chunk_list(struct usnic_vnic *vnic, /* Do Nothing */ } - res_chunk_list = kzalloc(sizeof(*res_chunk_list)*(res_lst_sz+1), + res_chunk_list = kcalloc(res_lst_sz + 1, sizeof(*res_chunk_list), GFP_ATOMIC); if (!res_chunk_list) return ERR_PTR(-ENOMEM); diff --git a/drivers/infiniband/hw/usnic/usnic_vnic.c b/drivers/infiniband/hw/usnic/usnic_vnic.c index e7b0030254da..ebe08f348453 100644 --- a/drivers/infiniband/hw/usnic/usnic_vnic.c +++ b/drivers/infiniband/hw/usnic/usnic_vnic.c @@ -312,7 +312,7 @@ static int usnic_vnic_alloc_res_chunk(struct usnic_vnic *vnic, } chunk->cnt = chunk->free_cnt = cnt; - chunk->res = kzalloc(sizeof(*(chunk->res))*cnt, GFP_KERNEL); + chunk->res = kcalloc(cnt, sizeof(*(chunk->res)), GFP_KERNEL); if (!chunk->res) return -ENOMEM; diff --git a/drivers/infiniband/sw/rdmavt/qp.c b/drivers/infiniband/sw/rdmavt/qp.c index 40046135c509..41183bd665ca 100644 --- a/drivers/infiniband/sw/rdmavt/qp.c +++ b/drivers/infiniband/sw/rdmavt/qp.c @@ -813,7 +813,7 @@ struct ib_qp *rvt_create_qp(struct ib_pd *ibpd, sz = sizeof(struct rvt_sge) * init_attr->cap.max_send_sge + sizeof(struct rvt_swqe); - swq = vzalloc_node(sqsize * sz, rdi->dparms.node); + swq = vzalloc_node(array_size(sz, sqsize), rdi->dparms.node); if (!swq) return ERR_PTR(-ENOMEM); @@ -836,11 +836,10 @@ struct ib_qp *rvt_create_qp(struct ib_pd *ibpd, RCU_INIT_POINTER(qp->next, NULL); if (init_attr->qp_type == IB_QPT_RC) { qp->s_ack_queue = - kzalloc_node( - sizeof(*qp->s_ack_queue) * - rvt_max_atomic(rdi), - GFP_KERNEL, - rdi->dparms.node); + kcalloc_node(rvt_max_atomic(rdi), + sizeof(*qp->s_ack_queue), + GFP_KERNEL, + rdi->dparms.node); if (!qp->s_ack_queue) goto bail_qp; } diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 962fbcb57dc7..6535d9beb24d 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -358,7 +358,8 @@ static int ipoib_cm_nonsrq_init_rx(struct net_device *dev, struct ib_cm_id *cm_i int ret; int i; - rx->rx_ring = vzalloc(ipoib_recvq_size * sizeof *rx->rx_ring); + rx->rx_ring = vzalloc(array_size(ipoib_recvq_size, + sizeof(*rx->rx_ring))); if (!rx->rx_ring) return -ENOMEM; @@ -1145,7 +1146,7 @@ static int ipoib_cm_tx_init(struct ipoib_cm_tx *p, u32 qpn, int ret; noio_flag = memalloc_noio_save(); - p->tx_ring = vzalloc(ipoib_sendq_size * sizeof(*p->tx_ring)); + p->tx_ring = vzalloc(array_size(ipoib_sendq_size, sizeof(*p->tx_ring))); if (!p->tx_ring) { memalloc_noio_restore(noio_flag); ret = -ENOMEM; @@ -1570,7 +1571,8 @@ static void ipoib_cm_create_srq(struct net_device *dev, int max_sge) return; } - priv->cm.srq_ring = vzalloc(ipoib_recvq_size * sizeof *priv->cm.srq_ring); + priv->cm.srq_ring = vzalloc(array_size(ipoib_recvq_size, + sizeof(*priv->cm.srq_ring))); if (!priv->cm.srq_ring) { ib_destroy_srq(priv->cm.srq); priv->cm.srq = NULL; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 2ce40a7ff604..26cde95bc0f3 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -1526,7 +1526,7 @@ static int ipoib_neigh_hash_init(struct ipoib_dev_priv *priv) return -ENOMEM; set_bit(IPOIB_STOP_NEIGH_GC, &priv->flags); size = roundup_pow_of_two(arp_tbl.gc_thresh3); - buckets = kzalloc(size * sizeof(*buckets), GFP_KERNEL); + buckets = kcalloc(size, sizeof(*buckets), GFP_KERNEL); if (!buckets) { kfree(htbl); return -ENOMEM; @@ -1704,12 +1704,14 @@ static int ipoib_dev_init_default(struct net_device *dev) ipoib_napi_add(dev); /* Allocate RX/TX "rings" to hold queued skbs */ - priv->rx_ring = kzalloc(ipoib_recvq_size * sizeof *priv->rx_ring, - GFP_KERNEL); + priv->rx_ring = kcalloc(ipoib_recvq_size, + sizeof(*priv->rx_ring), + GFP_KERNEL); if (!priv->rx_ring) goto out; - priv->tx_ring = vzalloc(ipoib_sendq_size * sizeof *priv->tx_ring); + priv->tx_ring = vzalloc(array_size(ipoib_sendq_size, + sizeof(*priv->tx_ring))); if (!priv->tx_ring) { pr_warn("%s: failed to allocate TX ring (%d entries)\n", priv->ca->name, ipoib_sendq_size); diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index ca858d6bd37a..2f6388596f88 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c @@ -258,8 +258,9 @@ int iser_alloc_rx_descriptors(struct iser_conn *iser_conn, goto alloc_login_buf_fail; iser_conn->num_rx_descs = session->cmds_max; - iser_conn->rx_descs = kmalloc(iser_conn->num_rx_descs * - sizeof(struct iser_rx_desc), GFP_KERNEL); + iser_conn->rx_descs = kmalloc_array(iser_conn->num_rx_descs, + sizeof(struct iser_rx_desc), + GFP_KERNEL); if (!iser_conn->rx_descs) goto rx_desc_alloc_fail; diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index f2f9318e1f49..cccbcf0eb035 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c @@ -181,8 +181,9 @@ isert_alloc_rx_descriptors(struct isert_conn *isert_conn) u64 dma_addr; int i, j; - isert_conn->rx_descs = kzalloc(ISERT_QP_MAX_RECV_DTOS * - sizeof(struct iser_rx_desc), GFP_KERNEL); + isert_conn->rx_descs = kcalloc(ISERT_QP_MAX_RECV_DTOS, + sizeof(struct iser_rx_desc), + GFP_KERNEL); if (!isert_conn->rx_descs) return -ENOMEM; diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index c35d2cd37d70..9786b24b956f 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -1035,16 +1035,17 @@ static int srp_alloc_req_data(struct srp_rdma_ch *ch) for (i = 0; i < target->req_ring_size; ++i) { req = &ch->req_ring[i]; - mr_list = kmalloc(target->mr_per_cmd * sizeof(void *), - GFP_KERNEL); + mr_list = kmalloc_array(target->mr_per_cmd, sizeof(void *), + GFP_KERNEL); if (!mr_list) goto out; if (srp_dev->use_fast_reg) { req->fr_list = mr_list; } else { req->fmr_list = mr_list; - req->map_page = kmalloc(srp_dev->max_pages_per_mr * - sizeof(void *), GFP_KERNEL); + req->map_page = kmalloc_array(srp_dev->max_pages_per_mr, + sizeof(void *), + GFP_KERNEL); if (!req->map_page) goto out; } diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index dfec0e1fac29..3081c629a7f7 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -720,7 +720,7 @@ static struct srpt_ioctx **srpt_alloc_ioctx_ring(struct srpt_device *sdev, WARN_ON(ioctx_size != sizeof(struct srpt_recv_ioctx) && ioctx_size != sizeof(struct srpt_send_ioctx)); - ring = kmalloc(ring_size * sizeof(ring[0]), GFP_KERNEL); + ring = kmalloc_array(ring_size, sizeof(ring[0]), GFP_KERNEL); if (!ring) goto out; for (i = 0; i < ring_size; ++i) { diff --git a/drivers/input/joystick/joydump.c b/drivers/input/joystick/joydump.c index d1c6e4846a4a..7f4dff9a566f 100644 --- a/drivers/input/joystick/joydump.c +++ b/drivers/input/joystick/joydump.c @@ -80,7 +80,7 @@ static int joydump_connect(struct gameport *gameport, struct gameport_driver *dr timeout = gameport_time(gameport, 10000); /* 10 ms */ - buf = kmalloc(BUF_SIZE * sizeof(struct joydump), GFP_KERNEL); + buf = kmalloc_array(BUF_SIZE, sizeof(struct joydump), GFP_KERNEL); if (!buf) { printk(KERN_INFO "joydump: no memory for testing\n"); goto jd_end; diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 2b469cc47a78..6bd97ffee761 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -747,4 +747,13 @@ config KEYBOARD_BCM To compile this driver as a module, choose M here: the module will be called bcm-keypad. +config KEYBOARD_MTK_PMIC + tristate "MediaTek PMIC keys support" + depends on MFD_MT6397 + help + Say Y here if you want to use the pmic keys (powerkey/homekey). + + To compile this driver as a module, choose M here: the + module will be called pmic-keys. + endif diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 8fab920afa58..182e92985dbf 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -40,6 +40,7 @@ obj-$(CONFIG_KEYBOARD_MATRIX) += matrix_keypad.o obj-$(CONFIG_KEYBOARD_MAX7359) += max7359_keypad.o obj-$(CONFIG_KEYBOARD_MCS) += mcs_touchkey.o obj-$(CONFIG_KEYBOARD_MPR121) += mpr121_touchkey.o +obj-$(CONFIG_KEYBOARD_MTK_PMIC) += mtk-pmic-keys.o obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o obj-$(CONFIG_KEYBOARD_NOMADIK) += nomadik-ske-keypad.o obj-$(CONFIG_KEYBOARD_NSPIRE) += nspire-keypad.o diff --git a/drivers/input/keyboard/clps711x-keypad.c b/drivers/input/keyboard/clps711x-keypad.c index 997e3e97f573..e319f745771a 100644 --- a/drivers/input/keyboard/clps711x-keypad.c +++ b/drivers/input/keyboard/clps711x-keypad.c @@ -109,8 +109,8 @@ static int clps711x_keypad_probe(struct platform_device *pdev) if (priv->row_count < 1) return -EINVAL; - priv->gpio_data = devm_kzalloc(dev, - sizeof(*priv->gpio_data) * priv->row_count, + priv->gpio_data = devm_kcalloc(dev, + priv->row_count, sizeof(*priv->gpio_data), GFP_KERNEL); if (!priv->gpio_data) return -ENOMEM; diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c index 41614c185918..f51ae09596ef 100644 --- a/drivers/input/keyboard/matrix_keypad.c +++ b/drivers/input/keyboard/matrix_keypad.c @@ -443,9 +443,9 @@ matrix_keypad_parse_dt(struct device *dev) of_property_read_u32(np, "col-scan-delay-us", &pdata->col_scan_delay_us); - gpios = devm_kzalloc(dev, - sizeof(unsigned int) * - (pdata->num_row_gpios + pdata->num_col_gpios), + gpios = devm_kcalloc(dev, + pdata->num_row_gpios + pdata->num_col_gpios, + sizeof(unsigned int), GFP_KERNEL); if (!gpios) { dev_err(dev, "could not allocate memory for gpios\n"); diff --git a/drivers/input/keyboard/mtk-pmic-keys.c b/drivers/input/keyboard/mtk-pmic-keys.c new file mode 100644 index 000000000000..02c67a1749fc --- /dev/null +++ b/drivers/input/keyboard/mtk-pmic-keys.c @@ -0,0 +1,339 @@ +/* + * Copyright (C) 2017 MediaTek, Inc. + * + * Author: Chen Zhong <chen.zhong@mediatek.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/kernel.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/regmap.h> +#include <linux/mfd/mt6323/registers.h> +#include <linux/mfd/mt6397/registers.h> +#include <linux/mfd/mt6397/core.h> + +#define MTK_PMIC_PWRKEY_RST_EN_MASK 0x1 +#define MTK_PMIC_PWRKEY_RST_EN_SHIFT 6 +#define MTK_PMIC_HOMEKEY_RST_EN_MASK 0x1 +#define MTK_PMIC_HOMEKEY_RST_EN_SHIFT 5 +#define MTK_PMIC_RST_DU_MASK 0x3 +#define MTK_PMIC_RST_DU_SHIFT 8 + +#define MTK_PMIC_PWRKEY_RST \ + (MTK_PMIC_PWRKEY_RST_EN_MASK << MTK_PMIC_PWRKEY_RST_EN_SHIFT) +#define MTK_PMIC_HOMEKEY_RST \ + (MTK_PMIC_HOMEKEY_RST_EN_MASK << MTK_PMIC_HOMEKEY_RST_EN_SHIFT) + +#define MTK_PMIC_PWRKEY_INDEX 0 +#define MTK_PMIC_HOMEKEY_INDEX 1 +#define MTK_PMIC_MAX_KEY_COUNT 2 + +struct mtk_pmic_keys_regs { + u32 deb_reg; + u32 deb_mask; + u32 intsel_reg; + u32 intsel_mask; +}; + +#define MTK_PMIC_KEYS_REGS(_deb_reg, _deb_mask, \ + _intsel_reg, _intsel_mask) \ +{ \ + .deb_reg = _deb_reg, \ + .deb_mask = _deb_mask, \ + .intsel_reg = _intsel_reg, \ + .intsel_mask = _intsel_mask, \ +} + +struct mtk_pmic_regs { + const struct mtk_pmic_keys_regs keys_regs[MTK_PMIC_MAX_KEY_COUNT]; + u32 pmic_rst_reg; +}; + +static const struct mtk_pmic_regs mt6397_regs = { + .keys_regs[MTK_PMIC_PWRKEY_INDEX] = + MTK_PMIC_KEYS_REGS(MT6397_CHRSTATUS, + 0x8, MT6397_INT_RSV, 0x10), + .keys_regs[MTK_PMIC_HOMEKEY_INDEX] = + MTK_PMIC_KEYS_REGS(MT6397_OCSTATUS2, + 0x10, MT6397_INT_RSV, 0x8), + .pmic_rst_reg = MT6397_TOP_RST_MISC, +}; + +static const struct mtk_pmic_regs mt6323_regs = { + .keys_regs[MTK_PMIC_PWRKEY_INDEX] = + MTK_PMIC_KEYS_REGS(MT6323_CHRSTATUS, + 0x2, MT6323_INT_MISC_CON, 0x10), + .keys_regs[MTK_PMIC_HOMEKEY_INDEX] = + MTK_PMIC_KEYS_REGS(MT6323_CHRSTATUS, + 0x4, MT6323_INT_MISC_CON, 0x8), + .pmic_rst_reg = MT6323_TOP_RST_MISC, +}; + +struct mtk_pmic_keys_info { + struct mtk_pmic_keys *keys; + const struct mtk_pmic_keys_regs *regs; + unsigned int keycode; + int irq; + bool wakeup:1; +}; + +struct mtk_pmic_keys { + struct input_dev *input_dev; + struct device *dev; + struct regmap *regmap; + struct mtk_pmic_keys_info keys[MTK_PMIC_MAX_KEY_COUNT]; +}; + +enum mtk_pmic_keys_lp_mode { + LP_DISABLE, + LP_ONEKEY, + LP_TWOKEY, +}; + +static void mtk_pmic_keys_lp_reset_setup(struct mtk_pmic_keys *keys, + u32 pmic_rst_reg) +{ + int ret; + u32 long_press_mode, long_press_debounce; + + ret = of_property_read_u32(keys->dev->of_node, + "power-off-time-sec", &long_press_debounce); + if (ret) + long_press_debounce = 0; + + regmap_update_bits(keys->regmap, pmic_rst_reg, + MTK_PMIC_RST_DU_MASK << MTK_PMIC_RST_DU_SHIFT, + long_press_debounce << MTK_PMIC_RST_DU_SHIFT); + + ret = of_property_read_u32(keys->dev->of_node, + "mediatek,long-press-mode", &long_press_mode); + if (ret) + long_press_mode = LP_DISABLE; + + switch (long_press_mode) { + case LP_ONEKEY: + regmap_update_bits(keys->regmap, pmic_rst_reg, + MTK_PMIC_PWRKEY_RST, + MTK_PMIC_PWRKEY_RST); + regmap_update_bits(keys->regmap, pmic_rst_reg, + MTK_PMIC_HOMEKEY_RST, + 0); + break; + case LP_TWOKEY: + regmap_update_bits(keys->regmap, pmic_rst_reg, + MTK_PMIC_PWRKEY_RST, + MTK_PMIC_PWRKEY_RST); + regmap_update_bits(keys->regmap, pmic_rst_reg, + MTK_PMIC_HOMEKEY_RST, + MTK_PMIC_HOMEKEY_RST); + break; + case LP_DISABLE: + regmap_update_bits(keys->regmap, pmic_rst_reg, + MTK_PMIC_PWRKEY_RST, + 0); + regmap_update_bits(keys->regmap, pmic_rst_reg, + MTK_PMIC_HOMEKEY_RST, + 0); + break; + default: + break; + } +} + +static irqreturn_t mtk_pmic_keys_irq_handler_thread(int irq, void *data) +{ + struct mtk_pmic_keys_info *info = data; + u32 key_deb, pressed; + + regmap_read(info->keys->regmap, info->regs->deb_reg, &key_deb); + + key_deb &= info->regs->deb_mask; + + pressed = !key_deb; + + input_report_key(info->keys->input_dev, info->keycode, pressed); + input_sync(info->keys->input_dev); + + dev_dbg(info->keys->dev, "(%s) key =%d using PMIC\n", + pressed ? "pressed" : "released", info->keycode); + + return IRQ_HANDLED; +} + +static int mtk_pmic_key_setup(struct mtk_pmic_keys *keys, + struct mtk_pmic_keys_info *info) +{ + int ret; + + info->keys = keys; + + ret = regmap_update_bits(keys->regmap, info->regs->intsel_reg, + info->regs->intsel_mask, + info->regs->intsel_mask); + if (ret < 0) + return ret; + + ret = devm_request_threaded_irq(keys->dev, info->irq, NULL, + mtk_pmic_keys_irq_handler_thread, + IRQF_ONESHOT | IRQF_TRIGGER_HIGH, + "mtk-pmic-keys", info); + if (ret) { + dev_err(keys->dev, "Failed to request IRQ: %d: %d\n", + info->irq, ret); + return ret; + } + + input_set_capability(keys->input_dev, EV_KEY, info->keycode); + + return 0; +} + +static int __maybe_unused mtk_pmic_keys_suspend(struct device *dev) +{ + struct mtk_pmic_keys *keys = dev_get_drvdata(dev); + int index; + + for (index = 0; index < MTK_PMIC_MAX_KEY_COUNT; index++) { + if (keys->keys[index].wakeup) + enable_irq_wake(keys->keys[index].irq); + } + + return 0; +} + +static int __maybe_unused mtk_pmic_keys_resume(struct device *dev) +{ + struct mtk_pmic_keys *keys = dev_get_drvdata(dev); + int index; + + for (index = 0; index < MTK_PMIC_MAX_KEY_COUNT; index++) { + if (keys->keys[index].wakeup) + disable_irq_wake(keys->keys[index].irq); + } + + return 0; +} + +static SIMPLE_DEV_PM_OPS(mtk_pmic_keys_pm_ops, mtk_pmic_keys_suspend, + mtk_pmic_keys_resume); + +static const struct of_device_id of_mtk_pmic_keys_match_tbl[] = { + { + .compatible = "mediatek,mt6397-keys", + .data = &mt6397_regs, + }, { + .compatible = "mediatek,mt6323-keys", + .data = &mt6323_regs, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(of, of_mtk_pmic_keys_match_tbl); + +static int mtk_pmic_keys_probe(struct platform_device *pdev) +{ + int error, index = 0; + unsigned int keycount; + struct mt6397_chip *pmic_chip = dev_get_drvdata(pdev->dev.parent); + struct device_node *node = pdev->dev.of_node, *child; + struct mtk_pmic_keys *keys; + const struct mtk_pmic_regs *mtk_pmic_regs; + struct input_dev *input_dev; + const struct of_device_id *of_id = + of_match_device(of_mtk_pmic_keys_match_tbl, &pdev->dev); + + keys = devm_kzalloc(&pdev->dev, sizeof(*keys), GFP_KERNEL); + if (!keys) + return -ENOMEM; + + keys->dev = &pdev->dev; + keys->regmap = pmic_chip->regmap; + mtk_pmic_regs = of_id->data; + + keys->input_dev = input_dev = devm_input_allocate_device(keys->dev); + if (!input_dev) { + dev_err(keys->dev, "input allocate device fail.\n"); + return -ENOMEM; + } + + input_dev->name = "mtk-pmic-keys"; + input_dev->id.bustype = BUS_HOST; + input_dev->id.vendor = 0x0001; + input_dev->id.product = 0x0001; + input_dev->id.version = 0x0001; + + keycount = of_get_available_child_count(node); + if (keycount > MTK_PMIC_MAX_KEY_COUNT) { + dev_err(keys->dev, "too many keys defined (%d)\n", keycount); + return -EINVAL; + } + + for_each_child_of_node(node, child) { + keys->keys[index].regs = &mtk_pmic_regs->keys_regs[index]; + + keys->keys[index].irq = platform_get_irq(pdev, index); + if (keys->keys[index].irq < 0) + return keys->keys[index].irq; + + error = of_property_read_u32(child, + "linux,keycodes", &keys->keys[index].keycode); + if (error) { + dev_err(keys->dev, + "failed to read key:%d linux,keycode property: %d\n", + index, error); + return error; + } + + if (of_property_read_bool(child, "wakeup-source")) + keys->keys[index].wakeup = true; + + error = mtk_pmic_key_setup(keys, &keys->keys[index]); + if (error) + return error; + + index++; + } + + error = input_register_device(input_dev); + if (error) { + dev_err(&pdev->dev, + "register input device failed (%d)\n", error); + return error; + } + + mtk_pmic_keys_lp_reset_setup(keys, mtk_pmic_regs->pmic_rst_reg); + + platform_set_drvdata(pdev, keys); + + return 0; +} + +static struct platform_driver pmic_keys_pdrv = { + .probe = mtk_pmic_keys_probe, + .driver = { + .name = "mtk-pmic-keys", + .of_match_table = of_mtk_pmic_keys_match_tbl, + .pm = &mtk_pmic_keys_pm_ops, + }, +}; + +module_platform_driver(pmic_keys_pdrv); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Chen Zhong <chen.zhong@mediatek.com>"); +MODULE_DESCRIPTION("MTK pmic-keys driver v0.1"); diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c index 940d38b08e6b..46406345742b 100644 --- a/drivers/input/keyboard/omap4-keypad.c +++ b/drivers/input/keyboard/omap4-keypad.c @@ -337,7 +337,8 @@ static int omap4_keypad_probe(struct platform_device *pdev) keypad_data->row_shift = get_count_order(keypad_data->cols); max_keys = keypad_data->rows << keypad_data->row_shift; - keypad_data->keymap = kzalloc(max_keys * sizeof(keypad_data->keymap[0]), + keypad_data->keymap = kcalloc(max_keys, + sizeof(keypad_data->keymap[0]), GFP_KERNEL); if (!keypad_data->keymap) { dev_err(&pdev->dev, "Not enough memory for keymap\n"); diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c index 316414465c77..1fe1aa2adf85 100644 --- a/drivers/input/keyboard/samsung-keypad.c +++ b/drivers/input/keyboard/samsung-keypad.c @@ -281,7 +281,7 @@ samsung_keypad_parse_dt(struct device *dev) key_count = of_get_child_count(np); keymap_data->keymap_size = key_count; - keymap = devm_kzalloc(dev, sizeof(uint32_t) * key_count, GFP_KERNEL); + keymap = devm_kcalloc(dev, key_count, sizeof(uint32_t), GFP_KERNEL); if (!keymap) { dev_err(dev, "could not allocate memory for keymap\n"); return ERR_PTR(-ENOMEM); diff --git a/drivers/input/matrix-keymap.c b/drivers/input/matrix-keymap.c index 8ccefc15c7a4..8b3a5758451e 100644 --- a/drivers/input/matrix-keymap.c +++ b/drivers/input/matrix-keymap.c @@ -170,8 +170,8 @@ int matrix_keypad_build_keymap(const struct matrix_keymap_data *keymap_data, return -EINVAL; if (!keymap) { - keymap = devm_kzalloc(input_dev->dev.parent, - max_keys * sizeof(*keymap), + keymap = devm_kcalloc(input_dev->dev.parent, + max_keys, sizeof(*keymap), GFP_KERNEL); if (!keymap) { dev_err(input_dev->dev.parent, diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c index 1588aecafff7..6d304381fc30 100644 --- a/drivers/input/misc/rotary_encoder.c +++ b/drivers/input/misc/rotary_encoder.c @@ -283,8 +283,8 @@ static int rotary_encoder_probe(struct platform_device *pdev) } encoder->irq = - devm_kzalloc(dev, - sizeof(*encoder->irq) * encoder->gpios->ndescs, + devm_kcalloc(dev, + encoder->gpios->ndescs, sizeof(*encoder->irq), GFP_KERNEL); if (!encoder->irq) return -ENOMEM; diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c index f5954981e9ee..7d29053dfb0f 100644 --- a/drivers/input/rmi4/rmi_driver.c +++ b/drivers/input/rmi4/rmi_driver.c @@ -636,9 +636,10 @@ int rmi_read_register_desc(struct rmi_device *d, u16 addr, rdesc->num_registers = bitmap_weight(rdesc->presense_map, RMI_REG_DESC_PRESENSE_BITS); - rdesc->registers = devm_kzalloc(&d->dev, rdesc->num_registers * - sizeof(struct rmi_register_desc_item), - GFP_KERNEL); + rdesc->registers = devm_kcalloc(&d->dev, + rdesc->num_registers, + sizeof(struct rmi_register_desc_item), + GFP_KERNEL); if (!rdesc->registers) return -ENOMEM; @@ -1061,7 +1062,7 @@ int rmi_probe_interrupts(struct rmi_driver_data *data) data->num_of_irq_regs = (data->irq_count + 7) / 8; size = BITS_TO_LONGS(data->irq_count) * sizeof(unsigned long); - data->irq_memory = devm_kzalloc(dev, size * 4, GFP_KERNEL); + data->irq_memory = devm_kcalloc(dev, size, 4, GFP_KERNEL); if (!data->irq_memory) { dev_err(dev, "Failed to allocate memory for irq masks.\n"); return -ENOMEM; diff --git a/drivers/input/rmi4/rmi_f11.c b/drivers/input/rmi4/rmi_f11.c index bc5e37f30ac1..12a233251793 100644 --- a/drivers/input/rmi4/rmi_f11.c +++ b/drivers/input/rmi4/rmi_f11.c @@ -1190,14 +1190,15 @@ static int rmi_f11_initialize(struct rmi_function *fn) f11->sensor.attn_size += f11->sensor.nbr_fingers * 2; /* allocate the in-kernel tracking buffers */ - sensor->tracking_pos = devm_kzalloc(&fn->dev, - sizeof(struct input_mt_pos) * sensor->nbr_fingers, + sensor->tracking_pos = devm_kcalloc(&fn->dev, + sensor->nbr_fingers, sizeof(struct input_mt_pos), + GFP_KERNEL); + sensor->tracking_slots = devm_kcalloc(&fn->dev, + sensor->nbr_fingers, sizeof(int), GFP_KERNEL); + sensor->objs = devm_kcalloc(&fn->dev, + sensor->nbr_fingers, + sizeof(struct rmi_2d_sensor_abs_object), GFP_KERNEL); - sensor->tracking_slots = devm_kzalloc(&fn->dev, - sizeof(int) * sensor->nbr_fingers, GFP_KERNEL); - sensor->objs = devm_kzalloc(&fn->dev, - sizeof(struct rmi_2d_sensor_abs_object) - * sensor->nbr_fingers, GFP_KERNEL); if (!sensor->tracking_pos || !sensor->tracking_slots || !sensor->objs) return -ENOMEM; diff --git a/drivers/input/rmi4/rmi_f12.c b/drivers/input/rmi4/rmi_f12.c index 8b0db086d68a..a3d1aa88f2a9 100644 --- a/drivers/input/rmi4/rmi_f12.c +++ b/drivers/input/rmi4/rmi_f12.c @@ -502,14 +502,15 @@ static int rmi_f12_probe(struct rmi_function *fn) } /* allocate the in-kernel tracking buffers */ - sensor->tracking_pos = devm_kzalloc(&fn->dev, - sizeof(struct input_mt_pos) * sensor->nbr_fingers, + sensor->tracking_pos = devm_kcalloc(&fn->dev, + sensor->nbr_fingers, sizeof(struct input_mt_pos), + GFP_KERNEL); + sensor->tracking_slots = devm_kcalloc(&fn->dev, + sensor->nbr_fingers, sizeof(int), GFP_KERNEL); + sensor->objs = devm_kcalloc(&fn->dev, + sensor->nbr_fingers, + sizeof(struct rmi_2d_sensor_abs_object), GFP_KERNEL); - sensor->tracking_slots = devm_kzalloc(&fn->dev, - sizeof(int) * sensor->nbr_fingers, GFP_KERNEL); - sensor->objs = devm_kzalloc(&fn->dev, - sizeof(struct rmi_2d_sensor_abs_object) - * sensor->nbr_fingers, GFP_KERNEL); if (!sensor->tracking_pos || !sensor->tracking_slots || !sensor->objs) return -ENOMEM; diff --git a/drivers/input/rmi4/rmi_f54.c b/drivers/input/rmi4/rmi_f54.c index 5343f2c08f15..e8a59d164019 100644 --- a/drivers/input/rmi4/rmi_f54.c +++ b/drivers/input/rmi4/rmi_f54.c @@ -685,7 +685,7 @@ static int rmi_f54_probe(struct rmi_function *fn) rx = f54->num_rx_electrodes; tx = f54->num_tx_electrodes; f54->report_data = devm_kzalloc(&fn->dev, - sizeof(u16) * tx * rx, + array3_size(tx, rx, sizeof(u16)), GFP_KERNEL); if (f54->report_data == NULL) return -ENOMEM; diff --git a/drivers/input/rmi4/rmi_spi.c b/drivers/input/rmi4/rmi_spi.c index 082defc329a8..33b8c6e7ac0a 100644 --- a/drivers/input/rmi4/rmi_spi.c +++ b/drivers/input/rmi4/rmi_spi.c @@ -69,7 +69,7 @@ static int rmi_spi_manage_pools(struct rmi_spi_xport *rmi_spi, int len) buf_size = RMI_SPI_XFER_SIZE_LIMIT; tmp = rmi_spi->rx_buf; - buf = devm_kzalloc(&spi->dev, buf_size * 2, + buf = devm_kcalloc(&spi->dev, buf_size, 2, GFP_KERNEL | GFP_DMA); if (!buf) return -ENOMEM; @@ -96,9 +96,10 @@ static int rmi_spi_manage_pools(struct rmi_spi_xport *rmi_spi, int len) * per byte delays. */ tmp = rmi_spi->rx_xfers; - xfer_buf = devm_kzalloc(&spi->dev, - (rmi_spi->rx_xfer_count + rmi_spi->tx_xfer_count) - * sizeof(struct spi_transfer), GFP_KERNEL); + xfer_buf = devm_kcalloc(&spi->dev, + rmi_spi->rx_xfer_count + rmi_spi->tx_xfer_count, + sizeof(struct spi_transfer), + GFP_KERNEL); if (!xfer_buf) return -ENOMEM; diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index 8ea77efb2e29..e055d228bfb9 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -107,7 +107,6 @@ config IOMMU_PGTABLES_L2 # AMD IOMMU support config AMD_IOMMU bool "AMD IOMMU support" - select DMA_DIRECT_OPS select SWIOTLB select PCI_MSI select PCI_ATS diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 0cea80be2888..596b95c50051 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -2596,32 +2596,51 @@ static void *alloc_coherent(struct device *dev, size_t size, unsigned long attrs) { u64 dma_mask = dev->coherent_dma_mask; - struct protection_domain *domain = get_domain(dev); - bool is_direct = false; - void *virt_addr; + struct protection_domain *domain; + struct dma_ops_domain *dma_dom; + struct page *page; + + domain = get_domain(dev); + if (PTR_ERR(domain) == -EINVAL) { + page = alloc_pages(flag, get_order(size)); + *dma_addr = page_to_phys(page); + return page_address(page); + } else if (IS_ERR(domain)) + return NULL; - if (IS_ERR(domain)) { - if (PTR_ERR(domain) != -EINVAL) + dma_dom = to_dma_ops_domain(domain); + size = PAGE_ALIGN(size); + dma_mask = dev->coherent_dma_mask; + flag &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32); + flag |= __GFP_ZERO; + + page = alloc_pages(flag | __GFP_NOWARN, get_order(size)); + if (!page) { + if (!gfpflags_allow_blocking(flag)) return NULL; - is_direct = true; - } - virt_addr = dma_direct_alloc(dev, size, dma_addr, flag, attrs); - if (!virt_addr || is_direct) - return virt_addr; + page = dma_alloc_from_contiguous(dev, size >> PAGE_SHIFT, + get_order(size), flag); + if (!page) + return NULL; + } if (!dma_mask) dma_mask = *dev->dma_mask; - *dma_addr = __map_single(dev, to_dma_ops_domain(domain), - virt_to_phys(virt_addr), PAGE_ALIGN(size), - DMA_BIDIRECTIONAL, dma_mask); + *dma_addr = __map_single(dev, dma_dom, page_to_phys(page), + size, DMA_BIDIRECTIONAL, dma_mask); + if (*dma_addr == AMD_IOMMU_MAPPING_ERROR) goto out_free; - return virt_addr; + + return page_address(page); out_free: - dma_direct_free(dev, size, virt_addr, *dma_addr, attrs); + + if (!dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT)) + __free_pages(page, get_order(size)); + return NULL; } @@ -2632,17 +2651,24 @@ static void free_coherent(struct device *dev, size_t size, void *virt_addr, dma_addr_t dma_addr, unsigned long attrs) { - struct protection_domain *domain = get_domain(dev); + struct protection_domain *domain; + struct dma_ops_domain *dma_dom; + struct page *page; + page = virt_to_page(virt_addr); size = PAGE_ALIGN(size); - if (!IS_ERR(domain)) { - struct dma_ops_domain *dma_dom = to_dma_ops_domain(domain); + domain = get_domain(dev); + if (IS_ERR(domain)) + goto free_mem; - __unmap_single(dma_dom, dma_addr, size, DMA_BIDIRECTIONAL); - } + dma_dom = to_dma_ops_domain(domain); + + __unmap_single(dma_dom, dma_addr, size, DMA_BIDIRECTIONAL); - dma_direct_free(dev, size, virt_addr, dma_addr, attrs); +free_mem: + if (!dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT)) + __free_pages(page, get_order(size)); } /* diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 69e7c60792a8..f7a96bcf94a6 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -2082,7 +2082,7 @@ static int arm_smmu_device_probe(struct platform_device *pdev) return -ENODEV; } - smmu->irqs = devm_kzalloc(dev, sizeof(*smmu->irqs) * num_irqs, + smmu->irqs = devm_kcalloc(dev, num_irqs, sizeof(*smmu->irqs), GFP_KERNEL); if (!smmu->irqs) { dev_err(dev, "failed to allocate %d irqs\n", num_irqs); diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index 4321f7704b23..75456b5aa825 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c @@ -1458,7 +1458,7 @@ int dmar_enable_qi(struct intel_iommu *iommu) qi->desc = page_address(desc_page); - qi->desc_status = kzalloc(QI_LENGTH * sizeof(int), GFP_ATOMIC); + qi->desc_status = kcalloc(QI_LENGTH, sizeof(int), GFP_ATOMIC); if (!qi->desc_status) { free_page((unsigned long) qi->desc); kfree(qi); diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 89e49a429c57..14e4b3722428 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -3189,7 +3189,7 @@ static int copy_translation_tables(struct intel_iommu *iommu) /* This is too big for the stack - allocate it from slab */ ctxt_table_entries = ext ? 512 : 256; ret = -ENOMEM; - ctxt_tbls = kzalloc(ctxt_table_entries * sizeof(void *), GFP_KERNEL); + ctxt_tbls = kcalloc(ctxt_table_entries, sizeof(void *), GFP_KERNEL); if (!ctxt_tbls) goto out_unmap; @@ -4032,7 +4032,7 @@ static int iommu_suspend(void) unsigned long flag; for_each_active_iommu(iommu, drhd) { - iommu->iommu_state = kzalloc(sizeof(u32) * MAX_SR_DMAR_REGS, + iommu->iommu_state = kcalloc(MAX_SR_DMAR_REGS, sizeof(u32), GFP_ATOMIC); if (!iommu->iommu_state) goto nomem; diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c index c33b7b104e72..af4a8e7fcd27 100644 --- a/drivers/iommu/omap-iommu.c +++ b/drivers/iommu/omap-iommu.c @@ -1455,7 +1455,7 @@ static int omap_iommu_add_device(struct device *dev) if (num_iommus < 0) return 0; - arch_data = kzalloc((num_iommus + 1) * sizeof(*arch_data), GFP_KERNEL); + arch_data = kcalloc(num_iommus + 1, sizeof(*arch_data), GFP_KERNEL); if (!arch_data) return -ENOMEM; diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c index 0468acfa131f..054cd2c8e9c8 100644 --- a/drivers/iommu/rockchip-iommu.c +++ b/drivers/iommu/rockchip-iommu.c @@ -1135,7 +1135,7 @@ static int rk_iommu_probe(struct platform_device *pdev) iommu->dev = dev; iommu->num_mmu = 0; - iommu->bases = devm_kzalloc(dev, sizeof(*iommu->bases) * num_res, + iommu->bases = devm_kcalloc(dev, num_res, sizeof(*iommu->bases), GFP_KERNEL); if (!iommu->bases) return -ENOMEM; diff --git a/drivers/iommu/tegra-gart.c b/drivers/iommu/tegra-gart.c index 89ec24c6952c..a004f6da35f2 100644 --- a/drivers/iommu/tegra-gart.c +++ b/drivers/iommu/tegra-gart.c @@ -465,7 +465,7 @@ static int tegra_gart_probe(struct platform_device *pdev) gart->iovmm_base = (dma_addr_t)res_remap->start; gart->page_count = (resource_size(res_remap) >> GART_PAGE_SHIFT); - gart->savedata = vmalloc(sizeof(u32) * gart->page_count); + gart->savedata = vmalloc(array_size(sizeof(u32), gart->page_count)); if (!gart->savedata) { dev_err(dev, "failed to allocate context save area\n"); return -ENOMEM; diff --git a/drivers/ipack/carriers/tpci200.c b/drivers/ipack/carriers/tpci200.c index 9b23843dcad4..a16b320739b4 100644 --- a/drivers/ipack/carriers/tpci200.c +++ b/drivers/ipack/carriers/tpci200.c @@ -457,8 +457,8 @@ static int tpci200_install(struct tpci200_board *tpci200) { int res; - tpci200->slots = kzalloc( - TPCI200_NB_SLOT * sizeof(struct tpci200_slot), GFP_KERNEL); + tpci200->slots = kcalloc(TPCI200_NB_SLOT, sizeof(struct tpci200_slot), + GFP_KERNEL); if (tpci200->slots == NULL) return -ENOMEM; diff --git a/drivers/irqchip/irq-alpine-msi.c b/drivers/irqchip/irq-alpine-msi.c index 63d980995d17..23a3b877f7f1 100644 --- a/drivers/irqchip/irq-alpine-msi.c +++ b/drivers/irqchip/irq-alpine-msi.c @@ -268,7 +268,8 @@ static int alpine_msix_init(struct device_node *node, goto err_priv; } - priv->msi_map = kzalloc(sizeof(*priv->msi_map) * BITS_TO_LONGS(priv->num_spis), + priv->msi_map = kcalloc(BITS_TO_LONGS(priv->num_spis), + sizeof(*priv->msi_map), GFP_KERNEL); if (!priv->msi_map) { ret = -ENOMEM; diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c index 1ff38aff9f29..0f52d44b3f69 100644 --- a/drivers/irqchip/irq-gic-v2m.c +++ b/drivers/irqchip/irq-gic-v2m.c @@ -361,7 +361,7 @@ static int __init gicv2m_init_one(struct fwnode_handle *fwnode, break; } - v2m->bm = kzalloc(sizeof(long) * BITS_TO_LONGS(v2m->nr_spis), + v2m->bm = kcalloc(BITS_TO_LONGS(v2m->nr_spis), sizeof(long), GFP_KERNEL); if (!v2m->bm) { ret = -ENOMEM; diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 5416f2b2ac21..5377d7e2afba 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -1239,7 +1239,7 @@ static int its_vlpi_map(struct irq_data *d, struct its_cmd_info *info) if (!its_dev->event_map.vm) { struct its_vlpi_map *maps; - maps = kzalloc(sizeof(*maps) * its_dev->event_map.nr_lpis, + maps = kcalloc(its_dev->event_map.nr_lpis, sizeof(*maps), GFP_KERNEL); if (!maps) { ret = -ENOMEM; @@ -1437,7 +1437,7 @@ static int __init its_lpi_init(u32 id_bits) { lpi_chunks = its_lpi_to_chunk(1UL << id_bits); - lpi_bitmap = kzalloc(BITS_TO_LONGS(lpi_chunks) * sizeof(long), + lpi_bitmap = kcalloc(BITS_TO_LONGS(lpi_chunks), sizeof(long), GFP_KERNEL); if (!lpi_bitmap) { lpi_chunks = 0; @@ -1471,7 +1471,8 @@ static unsigned long *its_lpi_alloc_chunks(int nr_irqs, int *base, int *nr_ids) if (!nr_chunks) goto out; - bitmap = kzalloc(BITS_TO_LONGS(nr_chunks * IRQS_PER_CHUNK) * sizeof (long), + bitmap = kcalloc(BITS_TO_LONGS(nr_chunks * IRQS_PER_CHUNK), + sizeof(long), GFP_ATOMIC); if (!bitmap) goto out; @@ -1823,7 +1824,7 @@ static int its_alloc_tables(struct its_node *its) static int its_alloc_collections(struct its_node *its) { - its->collections = kzalloc(nr_cpu_ids * sizeof(*its->collections), + its->collections = kcalloc(nr_cpu_ids, sizeof(*its->collections), GFP_KERNEL); if (!its->collections) return -ENOMEM; @@ -2124,10 +2125,10 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id, if (alloc_lpis) { lpi_map = its_lpi_alloc_chunks(nvecs, &lpi_base, &nr_lpis); if (lpi_map) - col_map = kzalloc(sizeof(*col_map) * nr_lpis, + col_map = kcalloc(nr_lpis, sizeof(*col_map), GFP_KERNEL); } else { - col_map = kzalloc(sizeof(*col_map) * nr_ites, GFP_KERNEL); + col_map = kcalloc(nr_ites, sizeof(*col_map), GFP_KERNEL); nr_lpis = 0; lpi_base = 0; } @@ -3183,7 +3184,7 @@ static int its_init_vpe_domain(void) its = list_first_entry(&its_nodes, struct its_node, entry); entries = roundup_pow_of_two(nr_cpu_ids); - vpe_proxy.vpes = kzalloc(sizeof(*vpe_proxy.vpes) * entries, + vpe_proxy.vpes = kcalloc(entries, sizeof(*vpe_proxy.vpes), GFP_KERNEL); if (!vpe_proxy.vpes) { pr_err("ITS: Can't allocate GICv4 proxy device array\n"); @@ -3567,8 +3568,8 @@ static void __init acpi_table_parse_srat_its(void) if (count <= 0) return; - its_srat_maps = kmalloc(count * sizeof(struct its_srat_map), - GFP_KERNEL); + its_srat_maps = kmalloc_array(count, sizeof(struct its_srat_map), + GFP_KERNEL); if (!its_srat_maps) { pr_warn("SRAT: Failed to allocate memory for its_srat_maps!\n"); return; diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 5a67ec084588..76ea56d779a1 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -1167,7 +1167,7 @@ static void __init gic_populate_ppi_partitions(struct device_node *gic_node) if (!nr_parts) goto out_put_node; - parts = kzalloc(sizeof(*parts) * nr_parts, GFP_KERNEL); + parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL); if (WARN_ON(!parts)) goto out_put_node; @@ -1289,7 +1289,8 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare if (of_property_read_u32(node, "#redistributor-regions", &nr_redist_regions)) nr_redist_regions = 1; - rdist_regs = kzalloc(sizeof(*rdist_regs) * nr_redist_regions, GFP_KERNEL); + rdist_regs = kcalloc(nr_redist_regions, sizeof(*rdist_regs), + GFP_KERNEL); if (!rdist_regs) { err = -ENOMEM; goto out_unmap_dist; diff --git a/drivers/irqchip/irq-imgpdc.c b/drivers/irqchip/irq-imgpdc.c index e80263e16c4c..d00489a4b54f 100644 --- a/drivers/irqchip/irq-imgpdc.c +++ b/drivers/irqchip/irq-imgpdc.c @@ -354,7 +354,7 @@ static int pdc_intc_probe(struct platform_device *pdev) priv->nr_syswakes = val; /* Get peripheral IRQ numbers */ - priv->perip_irqs = devm_kzalloc(&pdev->dev, 4 * priv->nr_perips, + priv->perip_irqs = devm_kcalloc(&pdev->dev, 4, priv->nr_perips, GFP_KERNEL); if (!priv->perip_irqs) { dev_err(&pdev->dev, "cannot allocate perip IRQ list\n"); diff --git a/drivers/irqchip/irq-mvebu-gicp.c b/drivers/irqchip/irq-mvebu-gicp.c index 4e17f7081efc..3be5c5dba1da 100644 --- a/drivers/irqchip/irq-mvebu-gicp.c +++ b/drivers/irqchip/irq-mvebu-gicp.c @@ -191,8 +191,8 @@ static int mvebu_gicp_probe(struct platform_device *pdev) gicp->spi_ranges_cnt = ret / 2; gicp->spi_ranges = - devm_kzalloc(&pdev->dev, - gicp->spi_ranges_cnt * + devm_kcalloc(&pdev->dev, + gicp->spi_ranges_cnt, sizeof(struct mvebu_gicp_spi_range), GFP_KERNEL); if (!gicp->spi_ranges) @@ -210,8 +210,8 @@ static int mvebu_gicp_probe(struct platform_device *pdev) gicp->spi_cnt += gicp->spi_ranges[i].count; } - gicp->spi_bitmap = devm_kzalloc(&pdev->dev, - BITS_TO_LONGS(gicp->spi_cnt) * sizeof(long), + gicp->spi_bitmap = devm_kcalloc(&pdev->dev, + BITS_TO_LONGS(gicp->spi_cnt), sizeof(long), GFP_KERNEL); if (!gicp->spi_bitmap) return -ENOMEM; diff --git a/drivers/irqchip/irq-partition-percpu.c b/drivers/irqchip/irq-partition-percpu.c index ccd72c2cbc23..1f7cc5933cd5 100644 --- a/drivers/irqchip/irq-partition-percpu.c +++ b/drivers/irqchip/irq-partition-percpu.c @@ -229,7 +229,7 @@ struct partition_desc *partition_create_desc(struct fwnode_handle *fwnode, goto out; desc->domain = d; - desc->bitmap = kzalloc(sizeof(long) * BITS_TO_LONGS(nr_parts), + desc->bitmap = kcalloc(BITS_TO_LONGS(nr_parts), sizeof(long), GFP_KERNEL); if (WARN_ON(!desc->bitmap)) goto out; diff --git a/drivers/irqchip/irq-s3c24xx.c b/drivers/irqchip/irq-s3c24xx.c index ec0e6a8cdb75..f6fd57ebe6e6 100644 --- a/drivers/irqchip/irq-s3c24xx.c +++ b/drivers/irqchip/irq-s3c24xx.c @@ -1261,7 +1261,7 @@ static int __init s3c_init_intc_of(struct device_node *np, return -ENOMEM; intc->domain = domain; - intc->irqs = kzalloc(sizeof(struct s3c_irq_data) * 32, + intc->irqs = kcalloc(32, sizeof(struct s3c_irq_data), GFP_KERNEL); if (!intc->irqs) { kfree(intc); diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index baa1ee2bc2ac..6e0c2814d032 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -1260,7 +1260,7 @@ static int __init capinc_tty_init(void) if (capi_ttyminors <= 0) capi_ttyminors = CAPINC_NR_PORTS; - capiminors = kzalloc(sizeof(struct capiminor *) * capi_ttyminors, + capiminors = kcalloc(capi_ttyminors, sizeof(struct capiminor *), GFP_KERNEL); if (!capiminors) return -ENOMEM; diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c index 7ac51798949d..ee510f901720 100644 --- a/drivers/isdn/capi/capidrv.c +++ b/drivers/isdn/capi/capidrv.c @@ -2268,7 +2268,8 @@ static int capidrv_addcontr(u16 contr, struct capi_profile *profp) strcpy(card->name, id); card->contrnr = contr; card->nbchan = profp->nbchannel; - card->bchans = kmalloc(sizeof(capidrv_bchan) * card->nbchan, GFP_ATOMIC); + card->bchans = kmalloc_array(card->nbchan, sizeof(capidrv_bchan), + GFP_ATOMIC); if (!card->bchans) { printk(KERN_WARNING "capidrv: (%s) Could not allocate bchan-structs.\n", id); diff --git a/drivers/isdn/gigaset/capi.c b/drivers/isdn/gigaset/capi.c index 56748af78c04..9cb2ab57fa4a 100644 --- a/drivers/isdn/gigaset/capi.c +++ b/drivers/isdn/gigaset/capi.c @@ -252,7 +252,7 @@ static inline void dump_rawmsg(enum debuglevel level, const char *tag, return; if (l > 64) l = 64; /* arbitrary limit */ - dbgline = kmalloc(3 * l, GFP_ATOMIC); + dbgline = kmalloc_array(3, l, GFP_ATOMIC); if (!dbgline) return; for (i = 0; i < l; i++) { @@ -272,7 +272,7 @@ static inline void dump_rawmsg(enum debuglevel level, const char *tag, return; if (l > 64) l = 64; /* arbitrary limit */ - dbgline = kmalloc(3 * l, GFP_ATOMIC); + dbgline = kmalloc_array(3, l, GFP_ATOMIC); if (!dbgline) return; data += CAPIMSG_LEN(data); @@ -1370,7 +1370,7 @@ static void do_connect_req(struct gigaset_capi_ctr *iif, cmsg->adr.adrPLCI |= (bcs->channel + 1) << 8; /* build command table */ - commands = kzalloc(AT_NUM * (sizeof *commands), GFP_KERNEL); + commands = kcalloc(AT_NUM, sizeof(*commands), GFP_KERNEL); if (!commands) goto oom; diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c index 15482c5de33c..76b5407b5277 100644 --- a/drivers/isdn/gigaset/common.c +++ b/drivers/isdn/gigaset/common.c @@ -710,7 +710,7 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, cs->mode = M_UNKNOWN; cs->mstate = MS_UNINITIALIZED; - cs->bcs = kmalloc(channels * sizeof(struct bc_state), GFP_KERNEL); + cs->bcs = kmalloc_array(channels, sizeof(struct bc_state), GFP_KERNEL); cs->inbuf = kmalloc(sizeof(struct inbuf_t), GFP_KERNEL); if (!cs->bcs || !cs->inbuf) { pr_err("out of memory\n"); @@ -1089,7 +1089,7 @@ struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors, drv->owner = owner; INIT_LIST_HEAD(&drv->list); - drv->cs = kmalloc(minors * sizeof *drv->cs, GFP_KERNEL); + drv->cs = kmalloc_array(minors, sizeof(*drv->cs), GFP_KERNEL); if (!drv->cs) goto error; diff --git a/drivers/isdn/gigaset/i4l.c b/drivers/isdn/gigaset/i4l.c index 2d75329007f1..b5b389e95edd 100644 --- a/drivers/isdn/gigaset/i4l.c +++ b/drivers/isdn/gigaset/i4l.c @@ -243,7 +243,7 @@ static int command_from_LL(isdn_ctrl *cntrl) dev_kfree_skb(bcs->rx_skb); gigaset_new_rx_skb(bcs); - commands = kzalloc(AT_NUM * (sizeof *commands), GFP_ATOMIC); + commands = kcalloc(AT_NUM, sizeof(*commands), GFP_ATOMIC); if (!commands) { gigaset_free_channel(bcs); dev_err(cs->dev, "ISDN_CMD_DIAL: out of memory\n"); diff --git a/drivers/isdn/hardware/avm/b1.c b/drivers/isdn/hardware/avm/b1.c index 5ee5489d3f15..4ac378e48902 100644 --- a/drivers/isdn/hardware/avm/b1.c +++ b/drivers/isdn/hardware/avm/b1.c @@ -72,7 +72,7 @@ avmcard *b1_alloc_card(int nr_controllers) if (!card) return NULL; - cinfo = kzalloc(sizeof(*cinfo) * nr_controllers, GFP_KERNEL); + cinfo = kcalloc(nr_controllers, sizeof(*cinfo), GFP_KERNEL); if (!cinfo) { kfree(card); return NULL; diff --git a/drivers/isdn/hisax/fsm.c b/drivers/isdn/hisax/fsm.c index 3e020ec0f65e..80ba82f77c63 100644 --- a/drivers/isdn/hisax/fsm.c +++ b/drivers/isdn/hisax/fsm.c @@ -27,7 +27,9 @@ FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount) int i; fsm->jumpmatrix = - kzalloc(sizeof(FSMFNPTR) * fsm->state_count * fsm->event_count, GFP_KERNEL); + kzalloc(array3_size(sizeof(FSMFNPTR), fsm->state_count, + fsm->event_count), + GFP_KERNEL); if (!fsm->jumpmatrix) return -ENOMEM; diff --git a/drivers/isdn/hisax/hfc_2bds0.c b/drivers/isdn/hisax/hfc_2bds0.c index 86b82172e992..3715fa0343db 100644 --- a/drivers/isdn/hisax/hfc_2bds0.c +++ b/drivers/isdn/hisax/hfc_2bds0.c @@ -1024,7 +1024,7 @@ static unsigned int int i; unsigned *send; - if (!(send = kmalloc(cnt * sizeof(unsigned int), GFP_ATOMIC))) { + if (!(send = kmalloc_array(cnt, sizeof(unsigned int), GFP_ATOMIC))) { printk(KERN_WARNING "HiSax: No memory for hfcd.send\n"); return (NULL); diff --git a/drivers/isdn/hisax/hfc_2bs0.c b/drivers/isdn/hisax/hfc_2bs0.c index 14dada42874e..34d59992839a 100644 --- a/drivers/isdn/hisax/hfc_2bs0.c +++ b/drivers/isdn/hisax/hfc_2bs0.c @@ -557,7 +557,8 @@ init_send(struct BCState *bcs) { int i; - if (!(bcs->hw.hfc.send = kmalloc(32 * sizeof(unsigned int), GFP_ATOMIC))) { + bcs->hw.hfc.send = kmalloc_array(32, sizeof(unsigned int), GFP_ATOMIC); + if (!bcs->hw.hfc.send) { printk(KERN_WARNING "HiSax: No memory for hfc.send\n"); return; diff --git a/drivers/isdn/hisax/netjet.c b/drivers/isdn/hisax/netjet.c index b7f54fa29228..e932a152c405 100644 --- a/drivers/isdn/hisax/netjet.c +++ b/drivers/isdn/hisax/netjet.c @@ -912,8 +912,10 @@ setstack_tiger(struct PStack *st, struct BCState *bcs) void inittiger(struct IsdnCardState *cs) { - if (!(cs->bcs[0].hw.tiger.send = kmalloc(NETJET_DMA_TXSIZE * sizeof(unsigned int), - GFP_KERNEL | GFP_DMA))) { + cs->bcs[0].hw.tiger.send = kmalloc_array(NETJET_DMA_TXSIZE, + sizeof(unsigned int), + GFP_KERNEL | GFP_DMA); + if (!cs->bcs[0].hw.tiger.send) { printk(KERN_WARNING "HiSax: No memory for tiger.send\n"); return; @@ -933,8 +935,10 @@ inittiger(struct IsdnCardState *cs) cs->hw.njet.base + NETJET_DMA_READ_IRQ); outl(virt_to_bus(cs->bcs[0].hw.tiger.s_end), cs->hw.njet.base + NETJET_DMA_READ_END); - if (!(cs->bcs[0].hw.tiger.rec = kmalloc(NETJET_DMA_RXSIZE * sizeof(unsigned int), - GFP_KERNEL | GFP_DMA))) { + cs->bcs[0].hw.tiger.rec = kmalloc_array(NETJET_DMA_RXSIZE, + sizeof(unsigned int), + GFP_KERNEL | GFP_DMA); + if (!cs->bcs[0].hw.tiger.rec) { printk(KERN_WARNING "HiSax: No memory for tiger.rec\n"); return; diff --git a/drivers/isdn/i4l/isdn_bsdcomp.c b/drivers/isdn/i4l/isdn_bsdcomp.c index 99012c047751..7f28b967ed19 100644 --- a/drivers/isdn/i4l/isdn_bsdcomp.c +++ b/drivers/isdn/i4l/isdn_bsdcomp.c @@ -340,7 +340,7 @@ static void *bsd_alloc(struct isdn_ppp_comp_data *data) * Allocate space for the dictionary. This may be more than one page in * length. */ - db->dict = vmalloc(hsize * sizeof(struct bsd_dict)); + db->dict = vmalloc(array_size(hsize, sizeof(struct bsd_dict))); if (!db->dict) { bsd_free(db); return NULL; @@ -353,7 +353,8 @@ static void *bsd_alloc(struct isdn_ppp_comp_data *data) if (!decomp) db->lens = NULL; else { - db->lens = vmalloc((maxmaxcode + 1) * sizeof(db->lens[0])); + db->lens = vmalloc(array_size(sizeof(db->lens[0]), + maxmaxcode + 1)); if (!db->lens) { bsd_free(db); return (NULL); diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c index 7c6f3f5d9d9a..7a501dbe7123 100644 --- a/drivers/isdn/i4l/isdn_common.c +++ b/drivers/isdn/i4l/isdn_common.c @@ -2070,14 +2070,14 @@ isdn_add_channels(isdn_driver_t *d, int drvidx, int n, int adding) if ((adding) && (d->rcverr)) kfree(d->rcverr); - if (!(d->rcverr = kzalloc(sizeof(int) * m, GFP_ATOMIC))) { + if (!(d->rcverr = kcalloc(m, sizeof(int), GFP_ATOMIC))) { printk(KERN_WARNING "register_isdn: Could not alloc rcverr\n"); return -1; } if ((adding) && (d->rcvcount)) kfree(d->rcvcount); - if (!(d->rcvcount = kzalloc(sizeof(int) * m, GFP_ATOMIC))) { + if (!(d->rcvcount = kcalloc(m, sizeof(int), GFP_ATOMIC))) { printk(KERN_WARNING "register_isdn: Could not alloc rcvcount\n"); if (!adding) kfree(d->rcverr); @@ -2089,7 +2089,8 @@ isdn_add_channels(isdn_driver_t *d, int drvidx, int n, int adding) skb_queue_purge(&d->rpqueue[j]); kfree(d->rpqueue); } - if (!(d->rpqueue = kmalloc(sizeof(struct sk_buff_head) * m, GFP_ATOMIC))) { + d->rpqueue = kmalloc_array(m, sizeof(struct sk_buff_head), GFP_ATOMIC); + if (!d->rpqueue) { printk(KERN_WARNING "register_isdn: Could not alloc rpqueue\n"); if (!adding) { kfree(d->rcvcount); @@ -2103,7 +2104,8 @@ isdn_add_channels(isdn_driver_t *d, int drvidx, int n, int adding) if ((adding) && (d->rcv_waitq)) kfree(d->rcv_waitq); - d->rcv_waitq = kmalloc(sizeof(wait_queue_head_t) * 2 * m, GFP_ATOMIC); + d->rcv_waitq = kmalloc(array3_size(sizeof(wait_queue_head_t), 2, m), + GFP_ATOMIC); if (!d->rcv_waitq) { printk(KERN_WARNING "register_isdn: Could not alloc rcv_waitq\n"); if (!adding) { diff --git a/drivers/isdn/mISDN/fsm.c b/drivers/isdn/mISDN/fsm.c index cabcb906e0b5..9a8d08d677a4 100644 --- a/drivers/isdn/mISDN/fsm.c +++ b/drivers/isdn/mISDN/fsm.c @@ -32,8 +32,10 @@ mISDN_FsmNew(struct Fsm *fsm, { int i; - fsm->jumpmatrix = kzalloc(sizeof(FSMFNPTR) * fsm->state_count * - fsm->event_count, GFP_KERNEL); + fsm->jumpmatrix = + kzalloc(array3_size(sizeof(FSMFNPTR), fsm->state_count, + fsm->event_count), + GFP_KERNEL); if (fsm->jumpmatrix == NULL) return -ENOMEM; diff --git a/drivers/leds/leds-adp5520.c b/drivers/leds/leds-adp5520.c index 853b2d3bdb17..7ecf080f73ad 100644 --- a/drivers/leds/leds-adp5520.c +++ b/drivers/leds/leds-adp5520.c @@ -108,7 +108,7 @@ static int adp5520_led_probe(struct platform_device *pdev) return -EFAULT; } - led = devm_kzalloc(&pdev->dev, sizeof(*led) * pdata->num_leds, + led = devm_kcalloc(&pdev->dev, pdata->num_leds, sizeof(*led), GFP_KERNEL); if (!led) return -ENOMEM; diff --git a/drivers/leds/leds-apu.c b/drivers/leds/leds-apu.c index 90eeedcbf371..8c93d68964c7 100644 --- a/drivers/leds/leds-apu.c +++ b/drivers/leds/leds-apu.c @@ -171,8 +171,8 @@ static int apu_led_config(struct device *dev, struct apu_led_pdata *apuld) int i; int err; - apu_led->pled = devm_kzalloc(dev, - sizeof(struct apu_led_priv) * apu_led->num_led_instances, + apu_led->pled = devm_kcalloc(dev, + apu_led->num_led_instances, sizeof(struct apu_led_priv), GFP_KERNEL); if (!apu_led->pled) diff --git a/drivers/leds/leds-cr0014114.c b/drivers/leds/leds-cr0014114.c index a4b1c1dcce7f..0e4262462cb9 100644 --- a/drivers/leds/leds-cr0014114.c +++ b/drivers/leds/leds-cr0014114.c @@ -237,8 +237,7 @@ static int cr0014114_probe(struct spi_device *spi) return -ENODEV; } - priv = devm_kzalloc(&spi->dev, - sizeof(*priv) + sizeof(*priv->leds) * count, + priv = devm_kzalloc(&spi->dev, struct_size(priv, leds, count), GFP_KERNEL); if (!priv) return -ENOMEM; diff --git a/drivers/leds/leds-da9052.c b/drivers/leds/leds-da9052.c index f8c7d82c2652..31d4c94e6fd8 100644 --- a/drivers/leds/leds-da9052.c +++ b/drivers/leds/leds-da9052.c @@ -113,8 +113,8 @@ static int da9052_led_probe(struct platform_device *pdev) goto err; } - led = devm_kzalloc(&pdev->dev, - sizeof(struct da9052_led) * pled->num_leds, + led = devm_kcalloc(&pdev->dev, + pled->num_leds, sizeof(struct da9052_led), GFP_KERNEL); if (!led) { error = -ENOMEM; diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c index 55c0517fbe03..99689b51a73d 100644 --- a/drivers/leds/leds-lp5521.c +++ b/drivers/leds/leds-lp5521.c @@ -533,8 +533,8 @@ static int lp5521_probe(struct i2c_client *client, if (!chip) return -ENOMEM; - led = devm_kzalloc(&client->dev, - sizeof(*led) * pdata->num_channels, GFP_KERNEL); + led = devm_kcalloc(&client->dev, + pdata->num_channels, sizeof(*led), GFP_KERNEL); if (!led) return -ENOMEM; diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c index 52b6f529e278..a2e74feee2b2 100644 --- a/drivers/leds/leds-lp5523.c +++ b/drivers/leds/leds-lp5523.c @@ -898,8 +898,8 @@ static int lp5523_probe(struct i2c_client *client, if (!chip) return -ENOMEM; - led = devm_kzalloc(&client->dev, - sizeof(*led) * pdata->num_channels, GFP_KERNEL); + led = devm_kcalloc(&client->dev, + pdata->num_channels, sizeof(*led), GFP_KERNEL); if (!led) return -ENOMEM; diff --git a/drivers/leds/leds-lp5562.c b/drivers/leds/leds-lp5562.c index 05ffa34fb6ad..2a9009fe5545 100644 --- a/drivers/leds/leds-lp5562.c +++ b/drivers/leds/leds-lp5562.c @@ -534,8 +534,8 @@ static int lp5562_probe(struct i2c_client *client, if (!chip) return -ENOMEM; - led = devm_kzalloc(&client->dev, - sizeof(*led) * pdata->num_channels, GFP_KERNEL); + led = devm_kcalloc(&client->dev, + pdata->num_channels, sizeof(*led), GFP_KERNEL); if (!led) return -ENOMEM; diff --git a/drivers/leds/leds-lp55xx-common.c b/drivers/leds/leds-lp55xx-common.c index 5377f22ff994..3d79a6380761 100644 --- a/drivers/leds/leds-lp55xx-common.c +++ b/drivers/leds/leds-lp55xx-common.c @@ -560,7 +560,7 @@ struct lp55xx_platform_data *lp55xx_of_populate_pdata(struct device *dev, return ERR_PTR(-EINVAL); } - cfg = devm_kzalloc(dev, sizeof(*cfg) * num_channels, GFP_KERNEL); + cfg = devm_kcalloc(dev, num_channels, sizeof(*cfg), GFP_KERNEL); if (!cfg) return ERR_PTR(-ENOMEM); diff --git a/drivers/leds/leds-lp8501.c b/drivers/leds/leds-lp8501.c index 3adb113cf02e..4c800b5989a9 100644 --- a/drivers/leds/leds-lp8501.c +++ b/drivers/leds/leds-lp8501.c @@ -327,8 +327,8 @@ static int lp8501_probe(struct i2c_client *client, if (!chip) return -ENOMEM; - led = devm_kzalloc(&client->dev, - sizeof(*led) * pdata->num_channels, GFP_KERNEL); + led = devm_kcalloc(&client->dev, + pdata->num_channels, sizeof(*led), GFP_KERNEL); if (!led) return -ENOMEM; diff --git a/drivers/leds/leds-lt3593.c b/drivers/leds/leds-lt3593.c index a7ff510cbdd0..5ec730a31b65 100644 --- a/drivers/leds/leds-lt3593.c +++ b/drivers/leds/leds-lt3593.c @@ -128,8 +128,8 @@ static int lt3593_led_probe(struct platform_device *pdev) if (!pdata) return -EBUSY; - leds_data = devm_kzalloc(&pdev->dev, - sizeof(struct lt3593_led_data) * pdata->num_leds, + leds_data = devm_kcalloc(&pdev->dev, + pdata->num_leds, sizeof(struct lt3593_led_data), GFP_KERNEL); if (!leds_data) return -ENOMEM; diff --git a/drivers/leds/leds-mc13783.c b/drivers/leds/leds-mc13783.c index 2421cf104991..47ad7de9553c 100644 --- a/drivers/leds/leds-mc13783.c +++ b/drivers/leds/leds-mc13783.c @@ -136,7 +136,7 @@ static struct mc13xxx_leds_platform_data __init *mc13xxx_led_probe_dt( pdata->num_leds = of_get_child_count(parent); - pdata->led = devm_kzalloc(dev, pdata->num_leds * sizeof(*pdata->led), + pdata->led = devm_kcalloc(dev, pdata->num_leds, sizeof(*pdata->led), GFP_KERNEL); if (!pdata->led) { ret = -ENOMEM; @@ -210,7 +210,7 @@ static int __init mc13xxx_led_probe(struct platform_device *pdev) return -EINVAL; } - leds->led = devm_kzalloc(dev, leds->num_leds * sizeof(*leds->led), + leds->led = devm_kcalloc(dev, leds->num_leds, sizeof(*leds->led), GFP_KERNEL); if (!leds->led) return -ENOMEM; diff --git a/drivers/leds/leds-mlxcpld.c b/drivers/leds/leds-mlxcpld.c index 281482e1d50f..f4721f8065f0 100644 --- a/drivers/leds/leds-mlxcpld.c +++ b/drivers/leds/leds-mlxcpld.c @@ -329,8 +329,10 @@ static int mlxcpld_led_config(struct device *dev, int i; int err; - cpld->pled = devm_kzalloc(dev, sizeof(struct mlxcpld_led_priv) * - cpld->num_led_instances, GFP_KERNEL); + cpld->pled = devm_kcalloc(dev, + cpld->num_led_instances, + sizeof(struct mlxcpld_led_priv), + GFP_KERNEL); if (!cpld->pled) return -ENOMEM; diff --git a/drivers/leds/leds-netxbig.c b/drivers/leds/leds-netxbig.c index f48b1aed9b4e..62fa0de526ee 100644 --- a/drivers/leds/leds-netxbig.c +++ b/drivers/leds/leds-netxbig.c @@ -335,7 +335,7 @@ static int gpio_ext_get_of_pdata(struct device *dev, struct device_node *np, return ret; } num_addr = ret; - addr = devm_kzalloc(dev, num_addr * sizeof(*addr), GFP_KERNEL); + addr = devm_kcalloc(dev, num_addr, sizeof(*addr), GFP_KERNEL); if (!addr) return -ENOMEM; @@ -355,7 +355,7 @@ static int gpio_ext_get_of_pdata(struct device *dev, struct device_node *np, return ret; } num_data = ret; - data = devm_kzalloc(dev, num_data * sizeof(*data), GFP_KERNEL); + data = devm_kcalloc(dev, num_data, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; @@ -415,7 +415,7 @@ static int netxbig_leds_get_of_pdata(struct device *dev, if (ret % 3) return -EINVAL; num_timers = ret / 3; - timers = devm_kzalloc(dev, num_timers * sizeof(*timers), + timers = devm_kcalloc(dev, num_timers, sizeof(*timers), GFP_KERNEL); if (!timers) return -ENOMEM; @@ -444,7 +444,7 @@ static int netxbig_leds_get_of_pdata(struct device *dev, return -ENODEV; } - leds = devm_kzalloc(dev, num_leds * sizeof(*leds), GFP_KERNEL); + leds = devm_kcalloc(dev, num_leds, sizeof(*leds), GFP_KERNEL); if (!leds) return -ENOMEM; @@ -470,8 +470,8 @@ static int netxbig_leds_get_of_pdata(struct device *dev, goto err_node_put; mode_val = - devm_kzalloc(dev, - NETXBIG_LED_MODE_NUM * sizeof(*mode_val), + devm_kcalloc(dev, + NETXBIG_LED_MODE_NUM, sizeof(*mode_val), GFP_KERNEL); if (!mode_val) { ret = -ENOMEM; @@ -560,8 +560,8 @@ static int netxbig_led_probe(struct platform_device *pdev) return ret; } - leds_data = devm_kzalloc(&pdev->dev, - pdata->num_leds * sizeof(*leds_data), + leds_data = devm_kcalloc(&pdev->dev, + pdata->num_leds, sizeof(*leds_data), GFP_KERNEL); if (!leds_data) return -ENOMEM; diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c index 506b75b190e7..14fe5cd43232 100644 --- a/drivers/leds/leds-ns2.c +++ b/drivers/leds/leds-ns2.c @@ -264,7 +264,7 @@ ns2_leds_get_of_pdata(struct device *dev, struct ns2_led_platform_data *pdata) if (!num_leds) return -ENODEV; - leds = devm_kzalloc(dev, num_leds * sizeof(struct ns2_led), + leds = devm_kcalloc(dev, num_leds, sizeof(struct ns2_led), GFP_KERNEL); if (!leds) return -ENOMEM; @@ -298,8 +298,9 @@ ns2_leds_get_of_pdata(struct device *dev, struct ns2_led_platform_data *pdata) } num_modes = ret / 3; - modval = devm_kzalloc(dev, - num_modes * sizeof(struct ns2_led_modval), + modval = devm_kcalloc(dev, + num_modes, + sizeof(struct ns2_led_modval), GFP_KERNEL); if (!modval) return -ENOMEM; diff --git a/drivers/leds/leds-pca955x.c b/drivers/leds/leds-pca955x.c index 78183f90820e..f51b356d4426 100644 --- a/drivers/leds/leds-pca955x.c +++ b/drivers/leds/leds-pca955x.c @@ -390,8 +390,8 @@ pca955x_pdata_of_init(struct i2c_client *client, struct pca955x_chipdef *chip) if (!pdata) return ERR_PTR(-ENOMEM); - pdata->leds = devm_kzalloc(&client->dev, - sizeof(struct pca955x_led) * chip->bits, + pdata->leds = devm_kcalloc(&client->dev, + chip->bits, sizeof(struct pca955x_led), GFP_KERNEL); if (!pdata->leds) return ERR_PTR(-ENOMEM); @@ -494,8 +494,8 @@ static int pca955x_probe(struct i2c_client *client, if (!pca955x) return -ENOMEM; - pca955x->leds = devm_kzalloc(&client->dev, - sizeof(*pca955x_led) * chip->bits, GFP_KERNEL); + pca955x->leds = devm_kcalloc(&client->dev, + chip->bits, sizeof(*pca955x_led), GFP_KERNEL); if (!pca955x->leds) return -ENOMEM; diff --git a/drivers/leds/leds-pca963x.c b/drivers/leds/leds-pca963x.c index 3bf9a1271819..5c0908113e38 100644 --- a/drivers/leds/leds-pca963x.c +++ b/drivers/leds/leds-pca963x.c @@ -300,8 +300,8 @@ pca963x_dt_init(struct i2c_client *client, struct pca963x_chipdef *chip) if (!count || count > chip->n_leds) return ERR_PTR(-ENODEV); - pca963x_leds = devm_kzalloc(&client->dev, - sizeof(struct led_info) * chip->n_leds, GFP_KERNEL); + pca963x_leds = devm_kcalloc(&client->dev, + chip->n_leds, sizeof(struct led_info), GFP_KERNEL); if (!pca963x_leds) return ERR_PTR(-ENOMEM); @@ -407,7 +407,7 @@ static int pca963x_probe(struct i2c_client *client, GFP_KERNEL); if (!pca963x_chip) return -ENOMEM; - pca963x = devm_kzalloc(&client->dev, chip->n_leds * sizeof(*pca963x), + pca963x = devm_kcalloc(&client->dev, chip->n_leds, sizeof(*pca963x), GFP_KERNEL); if (!pca963x) return -ENOMEM; diff --git a/drivers/leds/leds-tca6507.c b/drivers/leds/leds-tca6507.c index c12c16fb1b9c..8f343afa4787 100644 --- a/drivers/leds/leds-tca6507.c +++ b/drivers/leds/leds-tca6507.c @@ -697,8 +697,8 @@ tca6507_led_dt_init(struct i2c_client *client) if (!count || count > NUM_LEDS) return ERR_PTR(-ENODEV); - tca_leds = devm_kzalloc(&client->dev, - sizeof(struct led_info) * NUM_LEDS, GFP_KERNEL); + tca_leds = devm_kcalloc(&client->dev, + NUM_LEDS, sizeof(struct led_info), GFP_KERNEL); if (!tca_leds) return ERR_PTR(-ENOMEM); diff --git a/drivers/lightnvm/pblk-gc.c b/drivers/lightnvm/pblk-gc.c index 6a4883e40cc0..080469d90b40 100644 --- a/drivers/lightnvm/pblk-gc.c +++ b/drivers/lightnvm/pblk-gc.c @@ -88,7 +88,7 @@ static void pblk_gc_line_ws(struct work_struct *work) up(&gc->gc_sem); - gc_rq->data = vmalloc(gc_rq->nr_secs * geo->csecs); + gc_rq->data = vmalloc(array_size(gc_rq->nr_secs, geo->csecs)); if (!gc_rq->data) { pr_err("pblk: could not GC line:%d (%d/%d)\n", line->id, *line->vsc, gc_rq->nr_secs); diff --git a/drivers/lightnvm/pblk-init.c b/drivers/lightnvm/pblk-init.c index 491df0fa0835..b57f764d6a16 100644 --- a/drivers/lightnvm/pblk-init.c +++ b/drivers/lightnvm/pblk-init.c @@ -187,7 +187,7 @@ static int pblk_rwb_init(struct pblk *pblk) nr_entries = pblk_rb_calculate_size(buffer_size); - entries = vzalloc(nr_entries * sizeof(struct pblk_rb_entry)); + entries = vzalloc(array_size(nr_entries, sizeof(struct pblk_rb_entry))); if (!entries) return -ENOMEM; @@ -379,7 +379,7 @@ static int pblk_core_init(struct pblk *pblk) return -EINVAL; } - pblk->pad_dist = kzalloc((pblk->min_write_pgs - 1) * sizeof(atomic64_t), + pblk->pad_dist = kcalloc(pblk->min_write_pgs - 1, sizeof(atomic64_t), GFP_KERNEL); if (!pblk->pad_dist) return -ENOMEM; @@ -833,8 +833,8 @@ static int pblk_alloc_line_meta(struct pblk *pblk, struct pblk_line *line) goto free_blk_bitmap; - line->chks = kmalloc(lm->blk_per_line * sizeof(struct nvm_chk_meta), - GFP_KERNEL); + line->chks = kmalloc_array(lm->blk_per_line, + sizeof(struct nvm_chk_meta), GFP_KERNEL); if (!line->chks) goto free_erase_bitmap; diff --git a/drivers/lightnvm/pblk-recovery.c b/drivers/lightnvm/pblk-recovery.c index 598342833d0d..3a5069183859 100644 --- a/drivers/lightnvm/pblk-recovery.c +++ b/drivers/lightnvm/pblk-recovery.c @@ -260,7 +260,7 @@ static int pblk_recov_pad_oob(struct pblk *pblk, struct pblk_line *line, if (!pad_rq) return -ENOMEM; - data = vzalloc(pblk->max_write_pgs * geo->csecs); + data = vzalloc(array_size(pblk->max_write_pgs, geo->csecs)); if (!data) { ret = -ENOMEM; goto free_rq; diff --git a/drivers/mailbox/hi6220-mailbox.c b/drivers/mailbox/hi6220-mailbox.c index 519376d3534c..4fa9803cd204 100644 --- a/drivers/mailbox/hi6220-mailbox.c +++ b/drivers/mailbox/hi6220-mailbox.c @@ -282,13 +282,13 @@ static int hi6220_mbox_probe(struct platform_device *pdev) mbox->dev = dev; mbox->chan_num = MBOX_CHAN_MAX; - mbox->mchan = devm_kzalloc(dev, - mbox->chan_num * sizeof(*mbox->mchan), GFP_KERNEL); + mbox->mchan = devm_kcalloc(dev, + mbox->chan_num, sizeof(*mbox->mchan), GFP_KERNEL); if (!mbox->mchan) return -ENOMEM; - mbox->chan = devm_kzalloc(dev, - mbox->chan_num * sizeof(*mbox->chan), GFP_KERNEL); + mbox->chan = devm_kcalloc(dev, + mbox->chan_num, sizeof(*mbox->chan), GFP_KERNEL); if (!mbox->chan) return -ENOMEM; diff --git a/drivers/mailbox/mailbox-sti.c b/drivers/mailbox/mailbox-sti.c index 41bcd339b68a..779d41262ef0 100644 --- a/drivers/mailbox/mailbox-sti.c +++ b/drivers/mailbox/mailbox-sti.c @@ -442,8 +442,8 @@ static int sti_mbox_probe(struct platform_device *pdev) if (!mbox) return -ENOMEM; - chans = devm_kzalloc(&pdev->dev, - sizeof(*chans) * STI_MBOX_CHAN_MAX, GFP_KERNEL); + chans = devm_kcalloc(&pdev->dev, + STI_MBOX_CHAN_MAX, sizeof(*chans), GFP_KERNEL); if (!chans) return -ENOMEM; diff --git a/drivers/mailbox/omap-mailbox.c b/drivers/mailbox/omap-mailbox.c index 2517038a8452..e1e2c085e68e 100644 --- a/drivers/mailbox/omap-mailbox.c +++ b/drivers/mailbox/omap-mailbox.c @@ -729,7 +729,7 @@ static int omap_mbox_probe(struct platform_device *pdev) return -ENODEV; } - finfoblk = devm_kzalloc(&pdev->dev, info_count * sizeof(*finfoblk), + finfoblk = devm_kcalloc(&pdev->dev, info_count, sizeof(*finfoblk), GFP_KERNEL); if (!finfoblk) return -ENOMEM; @@ -773,23 +773,23 @@ static int omap_mbox_probe(struct platform_device *pdev) if (IS_ERR(mdev->mbox_base)) return PTR_ERR(mdev->mbox_base); - mdev->irq_ctx = devm_kzalloc(&pdev->dev, num_users * sizeof(u32), + mdev->irq_ctx = devm_kcalloc(&pdev->dev, num_users, sizeof(u32), GFP_KERNEL); if (!mdev->irq_ctx) return -ENOMEM; /* allocate one extra for marking end of list */ - list = devm_kzalloc(&pdev->dev, (info_count + 1) * sizeof(*list), + list = devm_kcalloc(&pdev->dev, info_count + 1, sizeof(*list), GFP_KERNEL); if (!list) return -ENOMEM; - chnls = devm_kzalloc(&pdev->dev, (info_count + 1) * sizeof(*chnls), + chnls = devm_kcalloc(&pdev->dev, info_count + 1, sizeof(*chnls), GFP_KERNEL); if (!chnls) return -ENOMEM; - mboxblk = devm_kzalloc(&pdev->dev, info_count * sizeof(*mbox), + mboxblk = devm_kcalloc(&pdev->dev, info_count, sizeof(*mbox), GFP_KERNEL); if (!mboxblk) return -ENOMEM; diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c index fc3c237daef2..311e91b1a14f 100644 --- a/drivers/mailbox/pcc.c +++ b/drivers/mailbox/pcc.c @@ -466,7 +466,8 @@ static int __init acpi_pcc_probe(void) return -EINVAL; } - pcc_mbox_channels = kzalloc(sizeof(struct mbox_chan) * count, GFP_KERNEL); + pcc_mbox_channels = kcalloc(count, sizeof(struct mbox_chan), + GFP_KERNEL); if (!pcc_mbox_channels) { pr_err("Could not allocate space for PCC mbox channels\n"); return -ENOMEM; diff --git a/drivers/mailbox/ti-msgmgr.c b/drivers/mailbox/ti-msgmgr.c index 78753a87ba4d..5d04738c3c8a 100644 --- a/drivers/mailbox/ti-msgmgr.c +++ b/drivers/mailbox/ti-msgmgr.c @@ -568,12 +568,12 @@ static int ti_msgmgr_probe(struct platform_device *pdev) } inst->num_valid_queues = queue_count; - qinst = devm_kzalloc(dev, sizeof(*qinst) * queue_count, GFP_KERNEL); + qinst = devm_kcalloc(dev, queue_count, sizeof(*qinst), GFP_KERNEL); if (!qinst) return -ENOMEM; inst->qinsts = qinst; - chans = devm_kzalloc(dev, sizeof(*chans) * queue_count, GFP_KERNEL); + chans = devm_kcalloc(dev, queue_count, sizeof(*chans), GFP_KERNEL); if (!chans) return -ENOMEM; inst->chans = chans; diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index edff083f7c4e..8b8c123cae66 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig @@ -334,6 +334,17 @@ config DM_CACHE_SMQ of less memory utilization, improved performance and increased adaptability in the face of changing workloads. +config DM_WRITECACHE + tristate "Writecache target" + depends on BLK_DEV_DM + ---help--- + The writecache target caches writes on persistent memory or SSD. + It is intended for databases or other programs that need extremely + low commit latency. + + The writecache target doesn't cache reads because reads are supposed + to be cached in standard RAM. + config DM_ERA tristate "Era target (EXPERIMENTAL)" depends on BLK_DEV_DM diff --git a/drivers/md/Makefile b/drivers/md/Makefile index 63255f3ebd97..822f4e8753bc 100644 --- a/drivers/md/Makefile +++ b/drivers/md/Makefile @@ -67,6 +67,7 @@ obj-$(CONFIG_DM_ERA) += dm-era.o obj-$(CONFIG_DM_LOG_WRITES) += dm-log-writes.o obj-$(CONFIG_DM_INTEGRITY) += dm-integrity.o obj-$(CONFIG_DM_ZONED) += dm-zoned.o +obj-$(CONFIG_DM_WRITECACHE) += dm-writecache.o ifeq ($(CONFIG_DM_UEVENT),y) dm-mod-objs += dm-uevent.o diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index a31e55bcc4e5..fa4058e43202 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -1715,7 +1715,7 @@ struct cache_set *bch_cache_set_alloc(struct cache_sb *sb) 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)) || + if (!(c->devices = kcalloc(c->nr_uuids, sizeof(void *), GFP_KERNEL)) || 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) * @@ -2041,10 +2041,11 @@ static int cache_alloc(struct cache *ca) !init_fifo(&ca->free[RESERVE_NONE], free, GFP_KERNEL) || !init_fifo(&ca->free_inc, free << 2, GFP_KERNEL) || !init_heap(&ca->heap, free << 3, GFP_KERNEL) || - !(ca->buckets = vzalloc(sizeof(struct bucket) * - ca->sb.nbuckets)) || - !(ca->prio_buckets = kzalloc(sizeof(uint64_t) * prio_buckets(ca) * - 2, GFP_KERNEL)) || + !(ca->buckets = vzalloc(array_size(sizeof(struct bucket), + ca->sb.nbuckets))) || + !(ca->prio_buckets = kzalloc(array3_size(sizeof(uint64_t), + prio_buckets(ca), 2), + GFP_KERNEL)) || !(ca->disk_buckets = alloc_bucket_pages(GFP_KERNEL, ca))) return -ENOMEM; diff --git a/drivers/md/bcache/sysfs.c b/drivers/md/bcache/sysfs.c index 8ccbc8f3b3af..225b15aa0340 100644 --- a/drivers/md/bcache/sysfs.c +++ b/drivers/md/bcache/sysfs.c @@ -881,7 +881,8 @@ SHOW(__bch_cache) uint16_t q[31], *p, *cached; ssize_t ret; - cached = p = vmalloc(ca->sb.nbuckets * sizeof(uint16_t)); + cached = p = vmalloc(array_size(sizeof(uint16_t), + ca->sb.nbuckets)); if (!p) return -ENOMEM; diff --git a/drivers/md/dm-bio-prison-v1.c b/drivers/md/dm-bio-prison-v1.c index e794e3662fdd..b5389890bbc3 100644 --- a/drivers/md/dm-bio-prison-v1.c +++ b/drivers/md/dm-bio-prison-v1.c @@ -19,8 +19,8 @@ struct dm_bio_prison { spinlock_t lock; - mempool_t cell_pool; struct rb_root cells; + mempool_t cell_pool; }; static struct kmem_cache *_cell_cache; diff --git a/drivers/md/dm-bio-prison-v2.c b/drivers/md/dm-bio-prison-v2.c index f866bc97b032..b092cdc8e1ae 100644 --- a/drivers/md/dm-bio-prison-v2.c +++ b/drivers/md/dm-bio-prison-v2.c @@ -21,8 +21,8 @@ struct dm_bio_prison_v2 { struct workqueue_struct *wq; spinlock_t lock; - mempool_t cell_pool; struct rb_root cells; + mempool_t cell_pool; }; static struct kmem_cache *_cell_cache; diff --git a/drivers/md/dm-cache-policy-smq.c b/drivers/md/dm-cache-policy-smq.c index 4ab23d0075f6..1b5b9ad9e492 100644 --- a/drivers/md/dm-cache-policy-smq.c +++ b/drivers/md/dm-cache-policy-smq.c @@ -69,7 +69,7 @@ static int space_init(struct entry_space *es, unsigned nr_entries) return 0; } - es->begin = vzalloc(sizeof(struct entry) * nr_entries); + es->begin = vzalloc(array_size(nr_entries, sizeof(struct entry))); if (!es->begin) return -ENOMEM; @@ -588,7 +588,7 @@ static int h_init(struct smq_hash_table *ht, struct entry_space *es, unsigned nr nr_buckets = roundup_pow_of_two(max(nr_entries / 4u, 16u)); ht->hash_bits = __ffs(nr_buckets); - ht->buckets = vmalloc(sizeof(*ht->buckets) * nr_buckets); + ht->buckets = vmalloc(array_size(nr_buckets, sizeof(*ht->buckets))); if (!ht->buckets) return -ENOMEM; diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c index 001c71248246..ce14a3d1f609 100644 --- a/drivers/md/dm-cache-target.c +++ b/drivers/md/dm-cache-target.c @@ -371,7 +371,13 @@ struct cache_stats { struct cache { struct dm_target *ti; - struct dm_target_callbacks callbacks; + spinlock_t lock; + + /* + * Fields for converting from sectors to blocks. + */ + int sectors_per_block_shift; + sector_t sectors_per_block; struct dm_cache_metadata *cmd; @@ -402,13 +408,11 @@ struct cache { dm_cblock_t cache_size; /* - * Fields for converting from sectors to blocks. + * Invalidation fields. */ - sector_t sectors_per_block; - int sectors_per_block_shift; + spinlock_t invalidation_lock; + struct list_head invalidation_requests; - spinlock_t lock; - struct bio_list deferred_bios; sector_t migration_threshold; wait_queue_head_t migration_wait; atomic_t nr_allocated_migrations; @@ -419,13 +423,11 @@ struct cache { */ atomic_t nr_io_migrations; + struct bio_list deferred_bios; + struct rw_semaphore quiesce_lock; - /* - * cache_size entries, dirty if set - */ - atomic_t nr_dirty; - unsigned long *dirty_bitset; + struct dm_target_callbacks callbacks; /* * origin_blocks entries, discarded if set. @@ -442,17 +444,27 @@ struct cache { const char **ctr_args; struct dm_kcopyd_client *copier; - struct workqueue_struct *wq; struct work_struct deferred_bio_worker; struct work_struct migration_worker; + struct workqueue_struct *wq; struct delayed_work waker; struct dm_bio_prison_v2 *prison; - struct bio_set bs; - mempool_t migration_pool; + /* + * cache_size entries, dirty if set + */ + unsigned long *dirty_bitset; + atomic_t nr_dirty; - struct dm_cache_policy *policy; unsigned policy_nr_args; + struct dm_cache_policy *policy; + + /* + * Cache features such as write-through. + */ + struct cache_features features; + + struct cache_stats stats; bool need_tick_bio:1; bool sized:1; @@ -461,25 +473,16 @@ struct cache { bool loaded_mappings:1; bool loaded_discards:1; - /* - * Cache features such as write-through. - */ - struct cache_features features; - - struct cache_stats stats; + struct rw_semaphore background_work_lock; - /* - * Invalidation fields. - */ - spinlock_t invalidation_lock; - struct list_head invalidation_requests; + struct batcher committer; + struct work_struct commit_ws; struct io_tracker tracker; - struct work_struct commit_ws; - struct batcher committer; + mempool_t migration_pool; - struct rw_semaphore background_work_lock; + struct bio_set bs; }; struct per_bio_data { diff --git a/drivers/md/dm-core.h b/drivers/md/dm-core.h index f21c5d21bf1b..7d480c930eaf 100644 --- a/drivers/md/dm-core.h +++ b/drivers/md/dm-core.h @@ -31,6 +31,9 @@ struct dm_kobject_holder { struct mapped_device { struct mutex suspend_lock; + struct mutex table_devices_lock; + struct list_head table_devices; + /* * The current mapping (struct dm_table *). * Use dm_get_live_table{_fast} or take suspend_lock for @@ -38,17 +41,14 @@ struct mapped_device { */ void __rcu *map; - struct list_head table_devices; - struct mutex table_devices_lock; - unsigned long flags; - struct request_queue *queue; - int numa_node_id; - - enum dm_queue_mode type; /* Protect queue and type against concurrent access. */ struct mutex type_lock; + enum dm_queue_mode type; + + int numa_node_id; + struct request_queue *queue; atomic_t holders; atomic_t open_count; @@ -56,21 +56,21 @@ struct mapped_device { struct dm_target *immutable_target; struct target_type *immutable_target_type; + char name[16]; struct gendisk *disk; struct dax_device *dax_dev; - char name[16]; - - void *interface_ptr; /* * A list of ios that arrived while we were suspended. */ - atomic_t pending[2]; - wait_queue_head_t wait; struct work_struct work; + wait_queue_head_t wait; + atomic_t pending[2]; spinlock_t deferred_lock; struct bio_list deferred; + void *interface_ptr; + /* * Event handling. */ @@ -84,17 +84,17 @@ struct mapped_device { unsigned internal_suspend_count; /* - * Processing queue (flush) - */ - struct workqueue_struct *wq; - - /* * io objects are allocated from here. */ struct bio_set io_bs; struct bio_set bs; /* + * Processing queue (flush) + */ + struct workqueue_struct *wq; + + /* * freeze/thaw support require holding onto a super block */ struct super_block *frozen_sb; @@ -102,11 +102,11 @@ struct mapped_device { /* forced geometry settings */ struct hd_geometry geometry; - struct block_device *bdev; - /* kobject and completion */ struct dm_kobject_holder kobj_holder; + struct block_device *bdev; + /* zero-length flush that will be cloned and submitted to targets */ struct bio flush_bio; diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index da02f4d8e4b9..b61b069c33af 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -139,25 +139,13 @@ struct crypt_config { struct dm_dev *dev; sector_t start; - /* - * 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; - unsigned tag_pool_max_sectors; - struct percpu_counter n_allocated_pages; - struct bio_set bs; - struct mutex bio_alloc_lock; - struct workqueue_struct *io_queue; struct workqueue_struct *crypt_queue; - struct task_struct *write_thread; wait_queue_head_t write_thread_wait; + struct task_struct *write_thread; struct rb_root write_tree; char *cipher; @@ -213,6 +201,18 @@ struct crypt_config { unsigned int integrity_iv_size; unsigned int on_disk_tag_size; + /* + * pool for per bio private data, crypto requests, + * encryption requeusts/buffer pages and integrity tags + */ + unsigned tag_pool_max_sectors; + mempool_t tag_pool; + mempool_t req_pool; + mempool_t page_pool; + + struct bio_set bs; + struct mutex bio_alloc_lock; + u8 *authenc_key; /* space for keys in authenc() format (if used) */ u8 key[0]; }; @@ -1878,8 +1878,9 @@ static int crypt_alloc_tfms_skcipher(struct crypt_config *cc, char *ciphermode) unsigned i; int err; - cc->cipher_tfm.tfms = kzalloc(cc->tfms_count * - sizeof(struct crypto_skcipher *), GFP_KERNEL); + cc->cipher_tfm.tfms = kcalloc(cc->tfms_count, + sizeof(struct crypto_skcipher *), + GFP_KERNEL); if (!cc->cipher_tfm.tfms) return -ENOMEM; diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c index fc68c7aaef8e..86438b2f10dd 100644 --- a/drivers/md/dm-integrity.c +++ b/drivers/md/dm-integrity.c @@ -2448,7 +2448,9 @@ static struct scatterlist **dm_integrity_alloc_journal_scatterlist(struct dm_int struct scatterlist **sl; unsigned i; - sl = kvmalloc(ic->journal_sections * sizeof(struct scatterlist *), GFP_KERNEL | __GFP_ZERO); + sl = kvmalloc_array(ic->journal_sections, + sizeof(struct scatterlist *), + GFP_KERNEL | __GFP_ZERO); if (!sl) return NULL; @@ -2464,7 +2466,8 @@ static struct scatterlist **dm_integrity_alloc_journal_scatterlist(struct dm_int n_pages = (end_index - start_index + 1); - s = kvmalloc(n_pages * sizeof(struct scatterlist), GFP_KERNEL); + s = kvmalloc_array(n_pages, sizeof(struct scatterlist), + GFP_KERNEL); if (!s) { dm_integrity_free_journal_scatterlist(ic, sl); return NULL; @@ -2643,7 +2646,9 @@ static int create_journal(struct dm_integrity_c *ic, char **error) goto bad; } - sg = kvmalloc((ic->journal_pages + 1) * sizeof(struct scatterlist), GFP_KERNEL); + sg = kvmalloc_array(ic->journal_pages + 1, + sizeof(struct scatterlist), + GFP_KERNEL); if (!sg) { *error = "Unable to allocate sg list"; r = -ENOMEM; @@ -2709,7 +2714,9 @@ static int create_journal(struct dm_integrity_c *ic, char **error) r = -ENOMEM; goto bad; } - ic->sk_requests = kvmalloc(ic->journal_sections * sizeof(struct skcipher_request *), GFP_KERNEL | __GFP_ZERO); + ic->sk_requests = kvmalloc_array(ic->journal_sections, + sizeof(struct skcipher_request *), + GFP_KERNEL | __GFP_ZERO); if (!ic->sk_requests) { *error = "Unable to allocate sk requests"; r = -ENOMEM; @@ -2743,7 +2750,8 @@ static int create_journal(struct dm_integrity_c *ic, char **error) r = -ENOMEM; goto bad; } - section_req->iv = kmalloc(ivsize * 2, GFP_KERNEL); + section_req->iv = kmalloc_array(ivsize, 2, + GFP_KERNEL); if (!section_req->iv) { skcipher_request_free(section_req); *error = "Unable to allocate iv"; diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index 5acf77de5945..b810ea77e6b1 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c @@ -1344,7 +1344,8 @@ static int table_load(struct file *filp, struct dm_ioctl *param, size_t param_si goto err_unlock_md_type; } } else if (!is_valid_type(dm_get_md_type(md), dm_table_get_type(t))) { - DMWARN("can't change device type after initial table load."); + DMWARN("can't change device type (old=%u vs new=%u) after initial table load.", + dm_get_md_type(md), dm_table_get_type(t)); r = -EINVAL; goto err_unlock_md_type; } diff --git a/drivers/md/dm-kcopyd.c b/drivers/md/dm-kcopyd.c index ce7efc7434be..3c7547a3c371 100644 --- a/drivers/md/dm-kcopyd.c +++ b/drivers/md/dm-kcopyd.c @@ -45,7 +45,6 @@ struct dm_kcopyd_client { struct dm_io_client *io_client; wait_queue_head_t destroyq; - atomic_t nr_jobs; mempool_t job_pool; @@ -54,6 +53,8 @@ struct dm_kcopyd_client { struct dm_kcopyd_throttle *throttle; + atomic_t nr_jobs; + /* * We maintain three lists of jobs: * diff --git a/drivers/md/dm-region-hash.c b/drivers/md/dm-region-hash.c index abf3521b80a8..1f760451e6f4 100644 --- a/drivers/md/dm-region-hash.c +++ b/drivers/md/dm-region-hash.c @@ -63,27 +63,28 @@ struct dm_region_hash { /* hash table */ rwlock_t hash_lock; - mempool_t region_pool; unsigned mask; unsigned nr_buckets; unsigned prime; unsigned shift; struct list_head *buckets; + /* + * If there was a flush failure no regions can be marked clean. + */ + int flush_failure; + unsigned max_recovery; /* Max # of regions to recover in parallel */ spinlock_t region_lock; atomic_t recovery_in_flight; - struct semaphore recovery_count; struct list_head clean_regions; struct list_head quiesced_regions; struct list_head recovered_regions; struct list_head failed_recovered_regions; + struct semaphore recovery_count; - /* - * If there was a flush failure no regions can be marked clean. - */ - int flush_failure; + mempool_t region_pool; void *context; sector_t target_begin; @@ -202,7 +203,7 @@ struct dm_region_hash *dm_region_hash_create( rh->shift = RH_HASH_SHIFT; rh->prime = RH_HASH_MULT; - rh->buckets = vmalloc(nr_buckets * sizeof(*rh->buckets)); + rh->buckets = vmalloc(array_size(nr_buckets, sizeof(*rh->buckets))); if (!rh->buckets) { DMERR("unable to allocate region hash bucket memory"); kfree(rh); diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index f745404da721..97de7a7334d4 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c @@ -326,8 +326,8 @@ static int init_origin_hash(void) { int i; - _origins = kmalloc(ORIGIN_HASH_SIZE * sizeof(struct list_head), - GFP_KERNEL); + _origins = kmalloc_array(ORIGIN_HASH_SIZE, sizeof(struct list_head), + GFP_KERNEL); if (!_origins) { DMERR("unable to allocate memory for _origins"); return -ENOMEM; @@ -335,8 +335,9 @@ static int init_origin_hash(void) for (i = 0; i < ORIGIN_HASH_SIZE; i++) INIT_LIST_HEAD(_origins + i); - _dm_origins = kmalloc(ORIGIN_HASH_SIZE * sizeof(struct list_head), - GFP_KERNEL); + _dm_origins = kmalloc_array(ORIGIN_HASH_SIZE, + sizeof(struct list_head), + GFP_KERNEL); if (!_dm_origins) { DMERR("unable to allocate memory for _dm_origins"); kfree(_origins); diff --git a/drivers/md/dm-stats.c b/drivers/md/dm-stats.c index 56059fb56e2d..21de30b4e2a1 100644 --- a/drivers/md/dm-stats.c +++ b/drivers/md/dm-stats.c @@ -915,7 +915,9 @@ static int parse_histogram(const char *h, unsigned *n_histogram_entries, if (*q == ',') (*n_histogram_entries)++; - *histogram_boundaries = kmalloc(*n_histogram_entries * sizeof(unsigned long long), GFP_KERNEL); + *histogram_boundaries = kmalloc_array(*n_histogram_entries, + sizeof(unsigned long long), + GFP_KERNEL); if (!*histogram_boundaries) return -ENOMEM; diff --git a/drivers/md/dm-switch.c b/drivers/md/dm-switch.c index 7924a6a33ddc..fae35caf3672 100644 --- a/drivers/md/dm-switch.c +++ b/drivers/md/dm-switch.c @@ -114,7 +114,8 @@ static int alloc_region_table(struct dm_target *ti, unsigned nr_paths) return -EINVAL; } - sctx->region_table = vmalloc(nr_slots * sizeof(region_table_slot_t)); + sctx->region_table = vmalloc(array_size(nr_slots, + sizeof(region_table_slot_t))); if (!sctx->region_table) { ti->error = "Cannot allocate region table"; return -ENOMEM; diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index caa51dd351b6..938766794c2e 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -561,7 +561,7 @@ static char **realloc_argv(unsigned *size, char **old_argv) new_size = 8; gfp = GFP_NOIO; } - argv = kmalloc(new_size * sizeof(*argv), gfp); + argv = kmalloc_array(new_size, sizeof(*argv), gfp); if (argv) { memcpy(argv, old_argv, *size * sizeof(*argv)); *size = new_size; diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index 5772756c63c1..7945238df1c0 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -240,9 +240,9 @@ struct pool { struct dm_bio_prison *prison; struct dm_kcopyd_client *copier; + struct work_struct worker; struct workqueue_struct *wq; struct throttle throttle; - struct work_struct worker; struct delayed_work waker; struct delayed_work no_space_timeout; @@ -260,7 +260,6 @@ struct pool { struct dm_deferred_set *all_io_ds; struct dm_thin_new_mapping *next_mapping; - mempool_t mapping_pool; process_bio_fn process_bio; process_bio_fn process_discard; @@ -273,6 +272,8 @@ struct pool { process_mapping_fn process_prepared_discard_pt2; struct dm_bio_prison_cell **cell_sort_array; + + mempool_t mapping_pool; }; static enum pool_mode get_pool_mode(struct pool *pool); @@ -2939,7 +2940,9 @@ static struct pool *pool_create(struct mapped_device *pool_md, goto bad_mapping_pool; } - pool->cell_sort_array = vmalloc(sizeof(*pool->cell_sort_array) * CELL_SORT_ARRAY_SIZE); + pool->cell_sort_array = + vmalloc(array_size(CELL_SORT_ARRAY_SIZE, + sizeof(*pool->cell_sort_array))); if (!pool->cell_sort_array) { *error = "Error allocating cell sort array"; err_p = ERR_PTR(-ENOMEM); diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c index fc893f636a98..12decdbd722d 100644 --- a/drivers/md/dm-verity-target.c +++ b/drivers/md/dm-verity-target.c @@ -797,8 +797,9 @@ static int verity_alloc_most_once(struct dm_verity *v) return -E2BIG; } - v->validated_blocks = kvzalloc(BITS_TO_LONGS(v->data_blocks) * - sizeof(unsigned long), GFP_KERNEL); + v->validated_blocks = kvcalloc(BITS_TO_LONGS(v->data_blocks), + sizeof(unsigned long), + GFP_KERNEL); if (!v->validated_blocks) { ti->error = "failed to allocate bitset for check_at_most_once"; return -ENOMEM; diff --git a/drivers/md/dm-writecache.c b/drivers/md/dm-writecache.c new file mode 100644 index 000000000000..5961c7794ef3 --- /dev/null +++ b/drivers/md/dm-writecache.c @@ -0,0 +1,2305 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 Red Hat. All rights reserved. + * + * This file is released under the GPL. + */ + +#include <linux/device-mapper.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/vmalloc.h> +#include <linux/kthread.h> +#include <linux/dm-io.h> +#include <linux/dm-kcopyd.h> +#include <linux/dax.h> +#include <linux/pfn_t.h> +#include <linux/libnvdimm.h> + +#define DM_MSG_PREFIX "writecache" + +#define HIGH_WATERMARK 50 +#define LOW_WATERMARK 45 +#define MAX_WRITEBACK_JOBS 0 +#define ENDIO_LATENCY 16 +#define WRITEBACK_LATENCY 64 +#define AUTOCOMMIT_BLOCKS_SSD 65536 +#define AUTOCOMMIT_BLOCKS_PMEM 64 +#define AUTOCOMMIT_MSEC 1000 + +#define BITMAP_GRANULARITY 65536 +#if BITMAP_GRANULARITY < PAGE_SIZE +#undef BITMAP_GRANULARITY +#define BITMAP_GRANULARITY PAGE_SIZE +#endif + +#if IS_ENABLED(CONFIG_ARCH_HAS_PMEM_API) && IS_ENABLED(CONFIG_DAX_DRIVER) +#define DM_WRITECACHE_HAS_PMEM +#endif + +#ifdef DM_WRITECACHE_HAS_PMEM +#define pmem_assign(dest, src) \ +do { \ + typeof(dest) uniq = (src); \ + memcpy_flushcache(&(dest), &uniq, sizeof(dest)); \ +} while (0) +#else +#define pmem_assign(dest, src) ((dest) = (src)) +#endif + +#if defined(__HAVE_ARCH_MEMCPY_MCSAFE) && defined(DM_WRITECACHE_HAS_PMEM) +#define DM_WRITECACHE_HANDLE_HARDWARE_ERRORS +#endif + +#define MEMORY_SUPERBLOCK_MAGIC 0x23489321 +#define MEMORY_SUPERBLOCK_VERSION 1 + +struct wc_memory_entry { + __le64 original_sector; + __le64 seq_count; +}; + +struct wc_memory_superblock { + union { + struct { + __le32 magic; + __le32 version; + __le32 block_size; + __le32 pad; + __le64 n_blocks; + __le64 seq_count; + }; + __le64 padding[8]; + }; + struct wc_memory_entry entries[0]; +}; + +struct wc_entry { + struct rb_node rb_node; + struct list_head lru; + unsigned short wc_list_contiguous; + bool write_in_progress +#if BITS_PER_LONG == 64 + :1 +#endif + ; + unsigned long index +#if BITS_PER_LONG == 64 + :47 +#endif + ; +#ifdef DM_WRITECACHE_HANDLE_HARDWARE_ERRORS + uint64_t original_sector; + uint64_t seq_count; +#endif +}; + +#ifdef DM_WRITECACHE_HAS_PMEM +#define WC_MODE_PMEM(wc) ((wc)->pmem_mode) +#define WC_MODE_FUA(wc) ((wc)->writeback_fua) +#else +#define WC_MODE_PMEM(wc) false +#define WC_MODE_FUA(wc) false +#endif +#define WC_MODE_SORT_FREELIST(wc) (!WC_MODE_PMEM(wc)) + +struct dm_writecache { + struct mutex lock; + struct list_head lru; + union { + struct list_head freelist; + struct { + struct rb_root freetree; + struct wc_entry *current_free; + }; + }; + struct rb_root tree; + + size_t freelist_size; + size_t writeback_size; + size_t freelist_high_watermark; + size_t freelist_low_watermark; + + unsigned uncommitted_blocks; + unsigned autocommit_blocks; + unsigned max_writeback_jobs; + + int error; + + unsigned long autocommit_jiffies; + struct timer_list autocommit_timer; + struct wait_queue_head freelist_wait; + + atomic_t bio_in_progress[2]; + struct wait_queue_head bio_in_progress_wait[2]; + + struct dm_target *ti; + struct dm_dev *dev; + struct dm_dev *ssd_dev; + void *memory_map; + uint64_t memory_map_size; + size_t metadata_sectors; + size_t n_blocks; + uint64_t seq_count; + void *block_start; + struct wc_entry *entries; + unsigned block_size; + unsigned char block_size_bits; + + bool pmem_mode:1; + bool writeback_fua:1; + + bool overwrote_committed:1; + bool memory_vmapped:1; + + bool high_wm_percent_set:1; + bool low_wm_percent_set:1; + bool max_writeback_jobs_set:1; + bool autocommit_blocks_set:1; + bool autocommit_time_set:1; + bool writeback_fua_set:1; + bool flush_on_suspend:1; + + unsigned writeback_all; + struct workqueue_struct *writeback_wq; + struct work_struct writeback_work; + struct work_struct flush_work; + + struct dm_io_client *dm_io; + + raw_spinlock_t endio_list_lock; + struct list_head endio_list; + struct task_struct *endio_thread; + + struct task_struct *flush_thread; + struct bio_list flush_list; + + struct dm_kcopyd_client *dm_kcopyd; + unsigned long *dirty_bitmap; + unsigned dirty_bitmap_size; + + struct bio_set bio_set; + mempool_t copy_pool; +}; + +#define WB_LIST_INLINE 16 + +struct writeback_struct { + struct list_head endio_entry; + struct dm_writecache *wc; + struct wc_entry **wc_list; + unsigned wc_list_n; + unsigned page_offset; + struct page *page; + struct wc_entry *wc_list_inline[WB_LIST_INLINE]; + struct bio bio; +}; + +struct copy_struct { + struct list_head endio_entry; + struct dm_writecache *wc; + struct wc_entry *e; + unsigned n_entries; + int error; +}; + +DECLARE_DM_KCOPYD_THROTTLE_WITH_MODULE_PARM(dm_writecache_throttle, + "A percentage of time allocated for data copying"); + +static void wc_lock(struct dm_writecache *wc) +{ + mutex_lock(&wc->lock); +} + +static void wc_unlock(struct dm_writecache *wc) +{ + mutex_unlock(&wc->lock); +} + +#ifdef DM_WRITECACHE_HAS_PMEM +static int persistent_memory_claim(struct dm_writecache *wc) +{ + int r; + loff_t s; + long p, da; + pfn_t pfn; + int id; + struct page **pages; + + wc->memory_vmapped = false; + + if (!wc->ssd_dev->dax_dev) { + r = -EOPNOTSUPP; + goto err1; + } + s = wc->memory_map_size; + p = s >> PAGE_SHIFT; + if (!p) { + r = -EINVAL; + goto err1; + } + if (p != s >> PAGE_SHIFT) { + r = -EOVERFLOW; + goto err1; + } + + id = dax_read_lock(); + + da = dax_direct_access(wc->ssd_dev->dax_dev, 0, p, &wc->memory_map, &pfn); + if (da < 0) { + wc->memory_map = NULL; + r = da; + goto err2; + } + if (!pfn_t_has_page(pfn)) { + wc->memory_map = NULL; + r = -EOPNOTSUPP; + goto err2; + } + if (da != p) { + long i; + wc->memory_map = NULL; + pages = kvmalloc(p * sizeof(struct page *), GFP_KERNEL); + if (!pages) { + r = -ENOMEM; + goto err2; + } + i = 0; + do { + long daa; + void *dummy_addr; + daa = dax_direct_access(wc->ssd_dev->dax_dev, i, p - i, + &dummy_addr, &pfn); + if (daa <= 0) { + r = daa ? daa : -EINVAL; + goto err3; + } + if (!pfn_t_has_page(pfn)) { + r = -EOPNOTSUPP; + goto err3; + } + while (daa-- && i < p) { + pages[i++] = pfn_t_to_page(pfn); + pfn.val++; + } + } while (i < p); + wc->memory_map = vmap(pages, p, VM_MAP, PAGE_KERNEL); + if (!wc->memory_map) { + r = -ENOMEM; + goto err3; + } + kvfree(pages); + wc->memory_vmapped = true; + } + + dax_read_unlock(id); + return 0; +err3: + kvfree(pages); +err2: + dax_read_unlock(id); +err1: + return r; +} +#else +static int persistent_memory_claim(struct dm_writecache *wc) +{ + BUG(); +} +#endif + +static void persistent_memory_release(struct dm_writecache *wc) +{ + if (wc->memory_vmapped) + vunmap(wc->memory_map); +} + +static struct page *persistent_memory_page(void *addr) +{ + if (is_vmalloc_addr(addr)) + return vmalloc_to_page(addr); + else + return virt_to_page(addr); +} + +static unsigned persistent_memory_page_offset(void *addr) +{ + return (unsigned long)addr & (PAGE_SIZE - 1); +} + +static void persistent_memory_flush_cache(void *ptr, size_t size) +{ + if (is_vmalloc_addr(ptr)) + flush_kernel_vmap_range(ptr, size); +} + +static void persistent_memory_invalidate_cache(void *ptr, size_t size) +{ + if (is_vmalloc_addr(ptr)) + invalidate_kernel_vmap_range(ptr, size); +} + +static struct wc_memory_superblock *sb(struct dm_writecache *wc) +{ + return wc->memory_map; +} + +static struct wc_memory_entry *memory_entry(struct dm_writecache *wc, struct wc_entry *e) +{ + if (is_power_of_2(sizeof(struct wc_entry)) && 0) + return &sb(wc)->entries[e - wc->entries]; + else + return &sb(wc)->entries[e->index]; +} + +static void *memory_data(struct dm_writecache *wc, struct wc_entry *e) +{ + return (char *)wc->block_start + (e->index << wc->block_size_bits); +} + +static sector_t cache_sector(struct dm_writecache *wc, struct wc_entry *e) +{ + return wc->metadata_sectors + + ((sector_t)e->index << (wc->block_size_bits - SECTOR_SHIFT)); +} + +static uint64_t read_original_sector(struct dm_writecache *wc, struct wc_entry *e) +{ +#ifdef DM_WRITECACHE_HANDLE_HARDWARE_ERRORS + return e->original_sector; +#else + return le64_to_cpu(memory_entry(wc, e)->original_sector); +#endif +} + +static uint64_t read_seq_count(struct dm_writecache *wc, struct wc_entry *e) +{ +#ifdef DM_WRITECACHE_HANDLE_HARDWARE_ERRORS + return e->seq_count; +#else + return le64_to_cpu(memory_entry(wc, e)->seq_count); +#endif +} + +static void clear_seq_count(struct dm_writecache *wc, struct wc_entry *e) +{ +#ifdef DM_WRITECACHE_HANDLE_HARDWARE_ERRORS + e->seq_count = -1; +#endif + pmem_assign(memory_entry(wc, e)->seq_count, cpu_to_le64(-1)); +} + +static void write_original_sector_seq_count(struct dm_writecache *wc, struct wc_entry *e, + uint64_t original_sector, uint64_t seq_count) +{ + struct wc_memory_entry me; +#ifdef DM_WRITECACHE_HANDLE_HARDWARE_ERRORS + e->original_sector = original_sector; + e->seq_count = seq_count; +#endif + me.original_sector = cpu_to_le64(original_sector); + me.seq_count = cpu_to_le64(seq_count); + pmem_assign(*memory_entry(wc, e), me); +} + +#define writecache_error(wc, err, msg, arg...) \ +do { \ + if (!cmpxchg(&(wc)->error, 0, err)) \ + DMERR(msg, ##arg); \ + wake_up(&(wc)->freelist_wait); \ +} while (0) + +#define writecache_has_error(wc) (unlikely(READ_ONCE((wc)->error))) + +static void writecache_flush_all_metadata(struct dm_writecache *wc) +{ + if (!WC_MODE_PMEM(wc)) + memset(wc->dirty_bitmap, -1, wc->dirty_bitmap_size); +} + +static void writecache_flush_region(struct dm_writecache *wc, void *ptr, size_t size) +{ + if (!WC_MODE_PMEM(wc)) + __set_bit(((char *)ptr - (char *)wc->memory_map) / BITMAP_GRANULARITY, + wc->dirty_bitmap); +} + +static void writecache_disk_flush(struct dm_writecache *wc, struct dm_dev *dev); + +struct io_notify { + struct dm_writecache *wc; + struct completion c; + atomic_t count; +}; + +static void writecache_notify_io(unsigned long error, void *context) +{ + struct io_notify *endio = context; + + if (unlikely(error != 0)) + writecache_error(endio->wc, -EIO, "error writing metadata"); + BUG_ON(atomic_read(&endio->count) <= 0); + if (atomic_dec_and_test(&endio->count)) + complete(&endio->c); +} + +static void ssd_commit_flushed(struct dm_writecache *wc) +{ + struct dm_io_region region; + struct dm_io_request req; + struct io_notify endio = { + wc, + COMPLETION_INITIALIZER_ONSTACK(endio.c), + ATOMIC_INIT(1), + }; + unsigned bitmap_bits = wc->dirty_bitmap_size * BITS_PER_LONG; + unsigned i = 0; + + while (1) { + unsigned j; + i = find_next_bit(wc->dirty_bitmap, bitmap_bits, i); + if (unlikely(i == bitmap_bits)) + break; + j = find_next_zero_bit(wc->dirty_bitmap, bitmap_bits, i); + + region.bdev = wc->ssd_dev->bdev; + region.sector = (sector_t)i * (BITMAP_GRANULARITY >> SECTOR_SHIFT); + region.count = (sector_t)(j - i) * (BITMAP_GRANULARITY >> SECTOR_SHIFT); + + if (unlikely(region.sector >= wc->metadata_sectors)) + break; + if (unlikely(region.sector + region.count > wc->metadata_sectors)) + region.count = wc->metadata_sectors - region.sector; + + atomic_inc(&endio.count); + req.bi_op = REQ_OP_WRITE; + req.bi_op_flags = REQ_SYNC; + req.mem.type = DM_IO_VMA; + req.mem.ptr.vma = (char *)wc->memory_map + (size_t)i * BITMAP_GRANULARITY; + req.client = wc->dm_io; + req.notify.fn = writecache_notify_io; + req.notify.context = &endio; + + /* writing via async dm-io (implied by notify.fn above) won't return an error */ + (void) dm_io(&req, 1, ®ion, NULL); + i = j; + } + + writecache_notify_io(0, &endio); + wait_for_completion_io(&endio.c); + + writecache_disk_flush(wc, wc->ssd_dev); + + memset(wc->dirty_bitmap, 0, wc->dirty_bitmap_size); +} + +static void writecache_commit_flushed(struct dm_writecache *wc) +{ + if (WC_MODE_PMEM(wc)) + wmb(); + else + ssd_commit_flushed(wc); +} + +static void writecache_disk_flush(struct dm_writecache *wc, struct dm_dev *dev) +{ + int r; + struct dm_io_region region; + struct dm_io_request req; + + region.bdev = dev->bdev; + region.sector = 0; + region.count = 0; + req.bi_op = REQ_OP_WRITE; + req.bi_op_flags = REQ_PREFLUSH; + req.mem.type = DM_IO_KMEM; + req.mem.ptr.addr = NULL; + req.client = wc->dm_io; + req.notify.fn = NULL; + + r = dm_io(&req, 1, ®ion, NULL); + if (unlikely(r)) + writecache_error(wc, r, "error flushing metadata: %d", r); +} + +static void writecache_wait_for_ios(struct dm_writecache *wc, int direction) +{ + wait_event(wc->bio_in_progress_wait[direction], + !atomic_read(&wc->bio_in_progress[direction])); +} + +#define WFE_RETURN_FOLLOWING 1 +#define WFE_LOWEST_SEQ 2 + +static struct wc_entry *writecache_find_entry(struct dm_writecache *wc, + uint64_t block, int flags) +{ + struct wc_entry *e; + struct rb_node *node = wc->tree.rb_node; + + if (unlikely(!node)) + return NULL; + + while (1) { + e = container_of(node, struct wc_entry, rb_node); + if (read_original_sector(wc, e) == block) + break; + node = (read_original_sector(wc, e) >= block ? + e->rb_node.rb_left : e->rb_node.rb_right); + if (unlikely(!node)) { + if (!(flags & WFE_RETURN_FOLLOWING)) { + return NULL; + } + if (read_original_sector(wc, e) >= block) { + break; + } else { + node = rb_next(&e->rb_node); + if (unlikely(!node)) { + return NULL; + } + e = container_of(node, struct wc_entry, rb_node); + break; + } + } + } + + while (1) { + struct wc_entry *e2; + if (flags & WFE_LOWEST_SEQ) + node = rb_prev(&e->rb_node); + else + node = rb_next(&e->rb_node); + if (!node) + return e; + e2 = container_of(node, struct wc_entry, rb_node); + if (read_original_sector(wc, e2) != block) + return e; + e = e2; + } +} + +static void writecache_insert_entry(struct dm_writecache *wc, struct wc_entry *ins) +{ + struct wc_entry *e; + struct rb_node **node = &wc->tree.rb_node, *parent = NULL; + + while (*node) { + e = container_of(*node, struct wc_entry, rb_node); + parent = &e->rb_node; + if (read_original_sector(wc, e) > read_original_sector(wc, ins)) + node = &parent->rb_left; + else + node = &parent->rb_right; + } + rb_link_node(&ins->rb_node, parent, node); + rb_insert_color(&ins->rb_node, &wc->tree); + list_add(&ins->lru, &wc->lru); +} + +static void writecache_unlink(struct dm_writecache *wc, struct wc_entry *e) +{ + list_del(&e->lru); + rb_erase(&e->rb_node, &wc->tree); +} + +static void writecache_add_to_freelist(struct dm_writecache *wc, struct wc_entry *e) +{ + if (WC_MODE_SORT_FREELIST(wc)) { + struct rb_node **node = &wc->freetree.rb_node, *parent = NULL; + if (unlikely(!*node)) + wc->current_free = e; + while (*node) { + parent = *node; + if (&e->rb_node < *node) + node = &parent->rb_left; + else + node = &parent->rb_right; + } + rb_link_node(&e->rb_node, parent, node); + rb_insert_color(&e->rb_node, &wc->freetree); + } else { + list_add_tail(&e->lru, &wc->freelist); + } + wc->freelist_size++; +} + +static struct wc_entry *writecache_pop_from_freelist(struct dm_writecache *wc) +{ + struct wc_entry *e; + + if (WC_MODE_SORT_FREELIST(wc)) { + struct rb_node *next; + if (unlikely(!wc->current_free)) + return NULL; + e = wc->current_free; + next = rb_next(&e->rb_node); + rb_erase(&e->rb_node, &wc->freetree); + if (unlikely(!next)) + next = rb_first(&wc->freetree); + wc->current_free = next ? container_of(next, struct wc_entry, rb_node) : NULL; + } else { + if (unlikely(list_empty(&wc->freelist))) + return NULL; + e = container_of(wc->freelist.next, struct wc_entry, lru); + list_del(&e->lru); + } + wc->freelist_size--; + if (unlikely(wc->freelist_size + wc->writeback_size <= wc->freelist_high_watermark)) + queue_work(wc->writeback_wq, &wc->writeback_work); + + return e; +} + +static void writecache_free_entry(struct dm_writecache *wc, struct wc_entry *e) +{ + writecache_unlink(wc, e); + writecache_add_to_freelist(wc, e); + clear_seq_count(wc, e); + writecache_flush_region(wc, memory_entry(wc, e), sizeof(struct wc_memory_entry)); + if (unlikely(waitqueue_active(&wc->freelist_wait))) + wake_up(&wc->freelist_wait); +} + +static void writecache_wait_on_freelist(struct dm_writecache *wc) +{ + DEFINE_WAIT(wait); + + prepare_to_wait(&wc->freelist_wait, &wait, TASK_UNINTERRUPTIBLE); + wc_unlock(wc); + io_schedule(); + finish_wait(&wc->freelist_wait, &wait); + wc_lock(wc); +} + +static void writecache_poison_lists(struct dm_writecache *wc) +{ + /* + * Catch incorrect access to these values while the device is suspended. + */ + memset(&wc->tree, -1, sizeof wc->tree); + wc->lru.next = LIST_POISON1; + wc->lru.prev = LIST_POISON2; + wc->freelist.next = LIST_POISON1; + wc->freelist.prev = LIST_POISON2; +} + +static void writecache_flush_entry(struct dm_writecache *wc, struct wc_entry *e) +{ + writecache_flush_region(wc, memory_entry(wc, e), sizeof(struct wc_memory_entry)); + if (WC_MODE_PMEM(wc)) + writecache_flush_region(wc, memory_data(wc, e), wc->block_size); +} + +static bool writecache_entry_is_committed(struct dm_writecache *wc, struct wc_entry *e) +{ + return read_seq_count(wc, e) < wc->seq_count; +} + +static void writecache_flush(struct dm_writecache *wc) +{ + struct wc_entry *e, *e2; + bool need_flush_after_free; + + wc->uncommitted_blocks = 0; + del_timer(&wc->autocommit_timer); + + if (list_empty(&wc->lru)) + return; + + e = container_of(wc->lru.next, struct wc_entry, lru); + if (writecache_entry_is_committed(wc, e)) { + if (wc->overwrote_committed) { + writecache_wait_for_ios(wc, WRITE); + writecache_disk_flush(wc, wc->ssd_dev); + wc->overwrote_committed = false; + } + return; + } + while (1) { + writecache_flush_entry(wc, e); + if (unlikely(e->lru.next == &wc->lru)) + break; + e2 = container_of(e->lru.next, struct wc_entry, lru); + if (writecache_entry_is_committed(wc, e2)) + break; + e = e2; + cond_resched(); + } + writecache_commit_flushed(wc); + + writecache_wait_for_ios(wc, WRITE); + + wc->seq_count++; + pmem_assign(sb(wc)->seq_count, cpu_to_le64(wc->seq_count)); + writecache_flush_region(wc, &sb(wc)->seq_count, sizeof sb(wc)->seq_count); + writecache_commit_flushed(wc); + + wc->overwrote_committed = false; + + need_flush_after_free = false; + while (1) { + /* Free another committed entry with lower seq-count */ + struct rb_node *rb_node = rb_prev(&e->rb_node); + + if (rb_node) { + e2 = container_of(rb_node, struct wc_entry, rb_node); + if (read_original_sector(wc, e2) == read_original_sector(wc, e) && + likely(!e2->write_in_progress)) { + writecache_free_entry(wc, e2); + need_flush_after_free = true; + } + } + if (unlikely(e->lru.prev == &wc->lru)) + break; + e = container_of(e->lru.prev, struct wc_entry, lru); + cond_resched(); + } + + if (need_flush_after_free) + writecache_commit_flushed(wc); +} + +static void writecache_flush_work(struct work_struct *work) +{ + struct dm_writecache *wc = container_of(work, struct dm_writecache, flush_work); + + wc_lock(wc); + writecache_flush(wc); + wc_unlock(wc); +} + +static void writecache_autocommit_timer(struct timer_list *t) +{ + struct dm_writecache *wc = from_timer(wc, t, autocommit_timer); + if (!writecache_has_error(wc)) + queue_work(wc->writeback_wq, &wc->flush_work); +} + +static void writecache_schedule_autocommit(struct dm_writecache *wc) +{ + if (!timer_pending(&wc->autocommit_timer)) + mod_timer(&wc->autocommit_timer, jiffies + wc->autocommit_jiffies); +} + +static void writecache_discard(struct dm_writecache *wc, sector_t start, sector_t end) +{ + struct wc_entry *e; + bool discarded_something = false; + + e = writecache_find_entry(wc, start, WFE_RETURN_FOLLOWING | WFE_LOWEST_SEQ); + if (unlikely(!e)) + return; + + while (read_original_sector(wc, e) < end) { + struct rb_node *node = rb_next(&e->rb_node); + + if (likely(!e->write_in_progress)) { + if (!discarded_something) { + writecache_wait_for_ios(wc, READ); + writecache_wait_for_ios(wc, WRITE); + discarded_something = true; + } + writecache_free_entry(wc, e); + } + + if (!node) + break; + + e = container_of(node, struct wc_entry, rb_node); + } + + if (discarded_something) + writecache_commit_flushed(wc); +} + +static bool writecache_wait_for_writeback(struct dm_writecache *wc) +{ + if (wc->writeback_size) { + writecache_wait_on_freelist(wc); + return true; + } + return false; +} + +static void writecache_suspend(struct dm_target *ti) +{ + struct dm_writecache *wc = ti->private; + bool flush_on_suspend; + + del_timer_sync(&wc->autocommit_timer); + + wc_lock(wc); + writecache_flush(wc); + flush_on_suspend = wc->flush_on_suspend; + if (flush_on_suspend) { + wc->flush_on_suspend = false; + wc->writeback_all++; + queue_work(wc->writeback_wq, &wc->writeback_work); + } + wc_unlock(wc); + + flush_workqueue(wc->writeback_wq); + + wc_lock(wc); + if (flush_on_suspend) + wc->writeback_all--; + while (writecache_wait_for_writeback(wc)); + + if (WC_MODE_PMEM(wc)) + persistent_memory_flush_cache(wc->memory_map, wc->memory_map_size); + + writecache_poison_lists(wc); + + wc_unlock(wc); +} + +static int writecache_alloc_entries(struct dm_writecache *wc) +{ + size_t b; + + if (wc->entries) + return 0; + wc->entries = vmalloc(sizeof(struct wc_entry) * wc->n_blocks); + if (!wc->entries) + return -ENOMEM; + for (b = 0; b < wc->n_blocks; b++) { + struct wc_entry *e = &wc->entries[b]; + e->index = b; + e->write_in_progress = false; + } + + return 0; +} + +static void writecache_resume(struct dm_target *ti) +{ + struct dm_writecache *wc = ti->private; + size_t b; + bool need_flush = false; + __le64 sb_seq_count; + int r; + + wc_lock(wc); + + if (WC_MODE_PMEM(wc)) + persistent_memory_invalidate_cache(wc->memory_map, wc->memory_map_size); + + wc->tree = RB_ROOT; + INIT_LIST_HEAD(&wc->lru); + if (WC_MODE_SORT_FREELIST(wc)) { + wc->freetree = RB_ROOT; + wc->current_free = NULL; + } else { + INIT_LIST_HEAD(&wc->freelist); + } + wc->freelist_size = 0; + + r = memcpy_mcsafe(&sb_seq_count, &sb(wc)->seq_count, sizeof(uint64_t)); + if (r) { + writecache_error(wc, r, "hardware memory error when reading superblock: %d", r); + sb_seq_count = cpu_to_le64(0); + } + wc->seq_count = le64_to_cpu(sb_seq_count); + +#ifdef DM_WRITECACHE_HANDLE_HARDWARE_ERRORS + for (b = 0; b < wc->n_blocks; b++) { + struct wc_entry *e = &wc->entries[b]; + struct wc_memory_entry wme; + if (writecache_has_error(wc)) { + e->original_sector = -1; + e->seq_count = -1; + continue; + } + r = memcpy_mcsafe(&wme, memory_entry(wc, e), sizeof(struct wc_memory_entry)); + if (r) { + writecache_error(wc, r, "hardware memory error when reading metadata entry %lu: %d", + (unsigned long)b, r); + e->original_sector = -1; + e->seq_count = -1; + } else { + e->original_sector = le64_to_cpu(wme.original_sector); + e->seq_count = le64_to_cpu(wme.seq_count); + } + } +#endif + for (b = 0; b < wc->n_blocks; b++) { + struct wc_entry *e = &wc->entries[b]; + if (!writecache_entry_is_committed(wc, e)) { + if (read_seq_count(wc, e) != -1) { +erase_this: + clear_seq_count(wc, e); + need_flush = true; + } + writecache_add_to_freelist(wc, e); + } else { + struct wc_entry *old; + + old = writecache_find_entry(wc, read_original_sector(wc, e), 0); + if (!old) { + writecache_insert_entry(wc, e); + } else { + if (read_seq_count(wc, old) == read_seq_count(wc, e)) { + writecache_error(wc, -EINVAL, + "two identical entries, position %llu, sector %llu, sequence %llu", + (unsigned long long)b, (unsigned long long)read_original_sector(wc, e), + (unsigned long long)read_seq_count(wc, e)); + } + if (read_seq_count(wc, old) > read_seq_count(wc, e)) { + goto erase_this; + } else { + writecache_free_entry(wc, old); + writecache_insert_entry(wc, e); + need_flush = true; + } + } + } + cond_resched(); + } + + if (need_flush) { + writecache_flush_all_metadata(wc); + writecache_commit_flushed(wc); + } + + wc_unlock(wc); +} + +static int process_flush_mesg(unsigned argc, char **argv, struct dm_writecache *wc) +{ + if (argc != 1) + return -EINVAL; + + wc_lock(wc); + if (dm_suspended(wc->ti)) { + wc_unlock(wc); + return -EBUSY; + } + if (writecache_has_error(wc)) { + wc_unlock(wc); + return -EIO; + } + + writecache_flush(wc); + wc->writeback_all++; + queue_work(wc->writeback_wq, &wc->writeback_work); + wc_unlock(wc); + + flush_workqueue(wc->writeback_wq); + + wc_lock(wc); + wc->writeback_all--; + if (writecache_has_error(wc)) { + wc_unlock(wc); + return -EIO; + } + wc_unlock(wc); + + return 0; +} + +static int process_flush_on_suspend_mesg(unsigned argc, char **argv, struct dm_writecache *wc) +{ + if (argc != 1) + return -EINVAL; + + wc_lock(wc); + wc->flush_on_suspend = true; + wc_unlock(wc); + + return 0; +} + +static int writecache_message(struct dm_target *ti, unsigned argc, char **argv, + char *result, unsigned maxlen) +{ + int r = -EINVAL; + struct dm_writecache *wc = ti->private; + + if (!strcasecmp(argv[0], "flush")) + r = process_flush_mesg(argc, argv, wc); + else if (!strcasecmp(argv[0], "flush_on_suspend")) + r = process_flush_on_suspend_mesg(argc, argv, wc); + else + DMERR("unrecognised message received: %s", argv[0]); + + return r; +} + +static void bio_copy_block(struct dm_writecache *wc, struct bio *bio, void *data) +{ + void *buf; + unsigned long flags; + unsigned size; + int rw = bio_data_dir(bio); + unsigned remaining_size = wc->block_size; + + do { + struct bio_vec bv = bio_iter_iovec(bio, bio->bi_iter); + buf = bvec_kmap_irq(&bv, &flags); + size = bv.bv_len; + if (unlikely(size > remaining_size)) + size = remaining_size; + + if (rw == READ) { + int r; + r = memcpy_mcsafe(buf, data, size); + flush_dcache_page(bio_page(bio)); + if (unlikely(r)) { + writecache_error(wc, r, "hardware memory error when reading data: %d", r); + bio->bi_status = BLK_STS_IOERR; + } + } else { + flush_dcache_page(bio_page(bio)); + memcpy_flushcache(data, buf, size); + } + + bvec_kunmap_irq(buf, &flags); + + data = (char *)data + size; + remaining_size -= size; + bio_advance(bio, size); + } while (unlikely(remaining_size)); +} + +static int writecache_flush_thread(void *data) +{ + struct dm_writecache *wc = data; + + while (1) { + struct bio *bio; + + wc_lock(wc); + bio = bio_list_pop(&wc->flush_list); + if (!bio) { + set_current_state(TASK_INTERRUPTIBLE); + wc_unlock(wc); + + if (unlikely(kthread_should_stop())) { + set_current_state(TASK_RUNNING); + break; + } + + schedule(); + continue; + } + + if (bio_op(bio) == REQ_OP_DISCARD) { + writecache_discard(wc, bio->bi_iter.bi_sector, + bio_end_sector(bio)); + wc_unlock(wc); + bio_set_dev(bio, wc->dev->bdev); + generic_make_request(bio); + } else { + writecache_flush(wc); + wc_unlock(wc); + if (writecache_has_error(wc)) + bio->bi_status = BLK_STS_IOERR; + bio_endio(bio); + } + } + + return 0; +} + +static void writecache_offload_bio(struct dm_writecache *wc, struct bio *bio) +{ + if (bio_list_empty(&wc->flush_list)) + wake_up_process(wc->flush_thread); + bio_list_add(&wc->flush_list, bio); +} + +static int writecache_map(struct dm_target *ti, struct bio *bio) +{ + struct wc_entry *e; + struct dm_writecache *wc = ti->private; + + bio->bi_private = NULL; + + wc_lock(wc); + + if (unlikely(bio->bi_opf & REQ_PREFLUSH)) { + if (writecache_has_error(wc)) + goto unlock_error; + if (WC_MODE_PMEM(wc)) { + writecache_flush(wc); + if (writecache_has_error(wc)) + goto unlock_error; + goto unlock_submit; + } else { + writecache_offload_bio(wc, bio); + goto unlock_return; + } + } + + bio->bi_iter.bi_sector = dm_target_offset(ti, bio->bi_iter.bi_sector); + + if (unlikely((((unsigned)bio->bi_iter.bi_sector | bio_sectors(bio)) & + (wc->block_size / 512 - 1)) != 0)) { + DMERR("I/O is not aligned, sector %llu, size %u, block size %u", + (unsigned long long)bio->bi_iter.bi_sector, + bio->bi_iter.bi_size, wc->block_size); + goto unlock_error; + } + + if (unlikely(bio_op(bio) == REQ_OP_DISCARD)) { + if (writecache_has_error(wc)) + goto unlock_error; + if (WC_MODE_PMEM(wc)) { + writecache_discard(wc, bio->bi_iter.bi_sector, bio_end_sector(bio)); + goto unlock_remap_origin; + } else { + writecache_offload_bio(wc, bio); + goto unlock_return; + } + } + + if (bio_data_dir(bio) == READ) { +read_next_block: + e = writecache_find_entry(wc, bio->bi_iter.bi_sector, WFE_RETURN_FOLLOWING); + if (e && read_original_sector(wc, e) == bio->bi_iter.bi_sector) { + if (WC_MODE_PMEM(wc)) { + bio_copy_block(wc, bio, memory_data(wc, e)); + if (bio->bi_iter.bi_size) + goto read_next_block; + goto unlock_submit; + } else { + dm_accept_partial_bio(bio, wc->block_size >> SECTOR_SHIFT); + bio_set_dev(bio, wc->ssd_dev->bdev); + bio->bi_iter.bi_sector = cache_sector(wc, e); + if (!writecache_entry_is_committed(wc, e)) + writecache_wait_for_ios(wc, WRITE); + goto unlock_remap; + } + } else { + if (e) { + sector_t next_boundary = + read_original_sector(wc, e) - bio->bi_iter.bi_sector; + if (next_boundary < bio->bi_iter.bi_size >> SECTOR_SHIFT) { + dm_accept_partial_bio(bio, next_boundary); + } + } + goto unlock_remap_origin; + } + } else { + do { + if (writecache_has_error(wc)) + goto unlock_error; + e = writecache_find_entry(wc, bio->bi_iter.bi_sector, 0); + if (e) { + if (!writecache_entry_is_committed(wc, e)) + goto bio_copy; + if (!WC_MODE_PMEM(wc) && !e->write_in_progress) { + wc->overwrote_committed = true; + goto bio_copy; + } + } + e = writecache_pop_from_freelist(wc); + if (unlikely(!e)) { + writecache_wait_on_freelist(wc); + continue; + } + write_original_sector_seq_count(wc, e, bio->bi_iter.bi_sector, wc->seq_count); + writecache_insert_entry(wc, e); + wc->uncommitted_blocks++; +bio_copy: + if (WC_MODE_PMEM(wc)) { + bio_copy_block(wc, bio, memory_data(wc, e)); + } else { + dm_accept_partial_bio(bio, wc->block_size >> SECTOR_SHIFT); + bio_set_dev(bio, wc->ssd_dev->bdev); + bio->bi_iter.bi_sector = cache_sector(wc, e); + if (unlikely(wc->uncommitted_blocks >= wc->autocommit_blocks)) { + wc->uncommitted_blocks = 0; + queue_work(wc->writeback_wq, &wc->flush_work); + } else { + writecache_schedule_autocommit(wc); + } + goto unlock_remap; + } + } while (bio->bi_iter.bi_size); + + if (unlikely(wc->uncommitted_blocks >= wc->autocommit_blocks)) + writecache_flush(wc); + else + writecache_schedule_autocommit(wc); + goto unlock_submit; + } + +unlock_remap_origin: + bio_set_dev(bio, wc->dev->bdev); + wc_unlock(wc); + return DM_MAPIO_REMAPPED; + +unlock_remap: + /* make sure that writecache_end_io decrements bio_in_progress: */ + bio->bi_private = (void *)1; + atomic_inc(&wc->bio_in_progress[bio_data_dir(bio)]); + wc_unlock(wc); + return DM_MAPIO_REMAPPED; + +unlock_submit: + wc_unlock(wc); + bio_endio(bio); + return DM_MAPIO_SUBMITTED; + +unlock_return: + wc_unlock(wc); + return DM_MAPIO_SUBMITTED; + +unlock_error: + wc_unlock(wc); + bio_io_error(bio); + return DM_MAPIO_SUBMITTED; +} + +static int writecache_end_io(struct dm_target *ti, struct bio *bio, blk_status_t *status) +{ + struct dm_writecache *wc = ti->private; + + if (bio->bi_private != NULL) { + int dir = bio_data_dir(bio); + if (atomic_dec_and_test(&wc->bio_in_progress[dir])) + if (unlikely(waitqueue_active(&wc->bio_in_progress_wait[dir]))) + wake_up(&wc->bio_in_progress_wait[dir]); + } + return 0; +} + +static int writecache_iterate_devices(struct dm_target *ti, + iterate_devices_callout_fn fn, void *data) +{ + struct dm_writecache *wc = ti->private; + + return fn(ti, wc->dev, 0, ti->len, data); +} + +static void writecache_io_hints(struct dm_target *ti, struct queue_limits *limits) +{ + struct dm_writecache *wc = ti->private; + + if (limits->logical_block_size < wc->block_size) + limits->logical_block_size = wc->block_size; + + if (limits->physical_block_size < wc->block_size) + limits->physical_block_size = wc->block_size; + + if (limits->io_min < wc->block_size) + limits->io_min = wc->block_size; +} + + +static void writecache_writeback_endio(struct bio *bio) +{ + struct writeback_struct *wb = container_of(bio, struct writeback_struct, bio); + struct dm_writecache *wc = wb->wc; + unsigned long flags; + + raw_spin_lock_irqsave(&wc->endio_list_lock, flags); + if (unlikely(list_empty(&wc->endio_list))) + wake_up_process(wc->endio_thread); + list_add_tail(&wb->endio_entry, &wc->endio_list); + raw_spin_unlock_irqrestore(&wc->endio_list_lock, flags); +} + +static void writecache_copy_endio(int read_err, unsigned long write_err, void *ptr) +{ + struct copy_struct *c = ptr; + struct dm_writecache *wc = c->wc; + + c->error = likely(!(read_err | write_err)) ? 0 : -EIO; + + raw_spin_lock_irq(&wc->endio_list_lock); + if (unlikely(list_empty(&wc->endio_list))) + wake_up_process(wc->endio_thread); + list_add_tail(&c->endio_entry, &wc->endio_list); + raw_spin_unlock_irq(&wc->endio_list_lock); +} + +static void __writecache_endio_pmem(struct dm_writecache *wc, struct list_head *list) +{ + unsigned i; + struct writeback_struct *wb; + struct wc_entry *e; + unsigned long n_walked = 0; + + do { + wb = list_entry(list->next, struct writeback_struct, endio_entry); + list_del(&wb->endio_entry); + + if (unlikely(wb->bio.bi_status != BLK_STS_OK)) + writecache_error(wc, blk_status_to_errno(wb->bio.bi_status), + "write error %d", wb->bio.bi_status); + i = 0; + do { + e = wb->wc_list[i]; + BUG_ON(!e->write_in_progress); + e->write_in_progress = false; + INIT_LIST_HEAD(&e->lru); + if (!writecache_has_error(wc)) + writecache_free_entry(wc, e); + BUG_ON(!wc->writeback_size); + wc->writeback_size--; + n_walked++; + if (unlikely(n_walked >= ENDIO_LATENCY)) { + writecache_commit_flushed(wc); + wc_unlock(wc); + wc_lock(wc); + n_walked = 0; + } + } while (++i < wb->wc_list_n); + + if (wb->wc_list != wb->wc_list_inline) + kfree(wb->wc_list); + bio_put(&wb->bio); + } while (!list_empty(list)); +} + +static void __writecache_endio_ssd(struct dm_writecache *wc, struct list_head *list) +{ + struct copy_struct *c; + struct wc_entry *e; + + do { + c = list_entry(list->next, struct copy_struct, endio_entry); + list_del(&c->endio_entry); + + if (unlikely(c->error)) + writecache_error(wc, c->error, "copy error"); + + e = c->e; + do { + BUG_ON(!e->write_in_progress); + e->write_in_progress = false; + INIT_LIST_HEAD(&e->lru); + if (!writecache_has_error(wc)) + writecache_free_entry(wc, e); + + BUG_ON(!wc->writeback_size); + wc->writeback_size--; + e++; + } while (--c->n_entries); + mempool_free(c, &wc->copy_pool); + } while (!list_empty(list)); +} + +static int writecache_endio_thread(void *data) +{ + struct dm_writecache *wc = data; + + while (1) { + struct list_head list; + + raw_spin_lock_irq(&wc->endio_list_lock); + if (!list_empty(&wc->endio_list)) + goto pop_from_list; + set_current_state(TASK_INTERRUPTIBLE); + raw_spin_unlock_irq(&wc->endio_list_lock); + + if (unlikely(kthread_should_stop())) { + set_current_state(TASK_RUNNING); + break; + } + + schedule(); + + continue; + +pop_from_list: + list = wc->endio_list; + list.next->prev = list.prev->next = &list; + INIT_LIST_HEAD(&wc->endio_list); + raw_spin_unlock_irq(&wc->endio_list_lock); + + if (!WC_MODE_FUA(wc)) + writecache_disk_flush(wc, wc->dev); + + wc_lock(wc); + + if (WC_MODE_PMEM(wc)) { + __writecache_endio_pmem(wc, &list); + } else { + __writecache_endio_ssd(wc, &list); + writecache_wait_for_ios(wc, READ); + } + + writecache_commit_flushed(wc); + + wc_unlock(wc); + } + + return 0; +} + +static bool wc_add_block(struct writeback_struct *wb, struct wc_entry *e, gfp_t gfp) +{ + struct dm_writecache *wc = wb->wc; + unsigned block_size = wc->block_size; + void *address = memory_data(wc, e); + + persistent_memory_flush_cache(address, block_size); + return bio_add_page(&wb->bio, persistent_memory_page(address), + block_size, persistent_memory_page_offset(address)) != 0; +} + +struct writeback_list { + struct list_head list; + size_t size; +}; + +static void __writeback_throttle(struct dm_writecache *wc, struct writeback_list *wbl) +{ + if (unlikely(wc->max_writeback_jobs)) { + if (READ_ONCE(wc->writeback_size) - wbl->size >= wc->max_writeback_jobs) { + wc_lock(wc); + while (wc->writeback_size - wbl->size >= wc->max_writeback_jobs) + writecache_wait_on_freelist(wc); + wc_unlock(wc); + } + } + cond_resched(); +} + +static void __writecache_writeback_pmem(struct dm_writecache *wc, struct writeback_list *wbl) +{ + struct wc_entry *e, *f; + struct bio *bio; + struct writeback_struct *wb; + unsigned max_pages; + + while (wbl->size) { + wbl->size--; + e = container_of(wbl->list.prev, struct wc_entry, lru); + list_del(&e->lru); + + max_pages = e->wc_list_contiguous; + + bio = bio_alloc_bioset(GFP_NOIO, max_pages, &wc->bio_set); + wb = container_of(bio, struct writeback_struct, bio); + wb->wc = wc; + wb->bio.bi_end_io = writecache_writeback_endio; + bio_set_dev(&wb->bio, wc->dev->bdev); + wb->bio.bi_iter.bi_sector = read_original_sector(wc, e); + wb->page_offset = PAGE_SIZE; + if (max_pages <= WB_LIST_INLINE || + unlikely(!(wb->wc_list = kmalloc(max_pages * sizeof(struct wc_entry *), + GFP_NOIO | __GFP_NORETRY | + __GFP_NOMEMALLOC | __GFP_NOWARN)))) { + wb->wc_list = wb->wc_list_inline; + max_pages = WB_LIST_INLINE; + } + + BUG_ON(!wc_add_block(wb, e, GFP_NOIO)); + + wb->wc_list[0] = e; + wb->wc_list_n = 1; + + while (wbl->size && wb->wc_list_n < max_pages) { + f = container_of(wbl->list.prev, struct wc_entry, lru); + if (read_original_sector(wc, f) != + read_original_sector(wc, e) + (wc->block_size >> SECTOR_SHIFT)) + break; + if (!wc_add_block(wb, f, GFP_NOWAIT | __GFP_NOWARN)) + break; + wbl->size--; + list_del(&f->lru); + wb->wc_list[wb->wc_list_n++] = f; + e = f; + } + bio_set_op_attrs(&wb->bio, REQ_OP_WRITE, WC_MODE_FUA(wc) * REQ_FUA); + if (writecache_has_error(wc)) { + bio->bi_status = BLK_STS_IOERR; + bio_endio(&wb->bio); + } else { + submit_bio(&wb->bio); + } + + __writeback_throttle(wc, wbl); + } +} + +static void __writecache_writeback_ssd(struct dm_writecache *wc, struct writeback_list *wbl) +{ + struct wc_entry *e, *f; + struct dm_io_region from, to; + struct copy_struct *c; + + while (wbl->size) { + unsigned n_sectors; + + wbl->size--; + e = container_of(wbl->list.prev, struct wc_entry, lru); + list_del(&e->lru); + + n_sectors = e->wc_list_contiguous << (wc->block_size_bits - SECTOR_SHIFT); + + from.bdev = wc->ssd_dev->bdev; + from.sector = cache_sector(wc, e); + from.count = n_sectors; + to.bdev = wc->dev->bdev; + to.sector = read_original_sector(wc, e); + to.count = n_sectors; + + c = mempool_alloc(&wc->copy_pool, GFP_NOIO); + c->wc = wc; + c->e = e; + c->n_entries = e->wc_list_contiguous; + + while ((n_sectors -= wc->block_size >> SECTOR_SHIFT)) { + wbl->size--; + f = container_of(wbl->list.prev, struct wc_entry, lru); + BUG_ON(f != e + 1); + list_del(&f->lru); + e = f; + } + + dm_kcopyd_copy(wc->dm_kcopyd, &from, 1, &to, 0, writecache_copy_endio, c); + + __writeback_throttle(wc, wbl); + } +} + +static void writecache_writeback(struct work_struct *work) +{ + struct dm_writecache *wc = container_of(work, struct dm_writecache, writeback_work); + struct blk_plug plug; + struct wc_entry *e, *f, *g; + struct rb_node *node, *next_node; + struct list_head skipped; + struct writeback_list wbl; + unsigned long n_walked; + + wc_lock(wc); +restart: + if (writecache_has_error(wc)) { + wc_unlock(wc); + return; + } + + if (unlikely(wc->writeback_all)) { + if (writecache_wait_for_writeback(wc)) + goto restart; + } + + if (wc->overwrote_committed) { + writecache_wait_for_ios(wc, WRITE); + } + + n_walked = 0; + INIT_LIST_HEAD(&skipped); + INIT_LIST_HEAD(&wbl.list); + wbl.size = 0; + while (!list_empty(&wc->lru) && + (wc->writeback_all || + wc->freelist_size + wc->writeback_size <= wc->freelist_low_watermark)) { + + n_walked++; + if (unlikely(n_walked > WRITEBACK_LATENCY) && + likely(!wc->writeback_all) && likely(!dm_suspended(wc->ti))) { + queue_work(wc->writeback_wq, &wc->writeback_work); + break; + } + + e = container_of(wc->lru.prev, struct wc_entry, lru); + BUG_ON(e->write_in_progress); + if (unlikely(!writecache_entry_is_committed(wc, e))) { + writecache_flush(wc); + } + node = rb_prev(&e->rb_node); + if (node) { + f = container_of(node, struct wc_entry, rb_node); + if (unlikely(read_original_sector(wc, f) == + read_original_sector(wc, e))) { + BUG_ON(!f->write_in_progress); + list_del(&e->lru); + list_add(&e->lru, &skipped); + cond_resched(); + continue; + } + } + wc->writeback_size++; + list_del(&e->lru); + list_add(&e->lru, &wbl.list); + wbl.size++; + e->write_in_progress = true; + e->wc_list_contiguous = 1; + + f = e; + + while (1) { + next_node = rb_next(&f->rb_node); + if (unlikely(!next_node)) + break; + g = container_of(next_node, struct wc_entry, rb_node); + if (read_original_sector(wc, g) == + read_original_sector(wc, f)) { + f = g; + continue; + } + if (read_original_sector(wc, g) != + read_original_sector(wc, f) + (wc->block_size >> SECTOR_SHIFT)) + break; + if (unlikely(g->write_in_progress)) + break; + if (unlikely(!writecache_entry_is_committed(wc, g))) + break; + + if (!WC_MODE_PMEM(wc)) { + if (g != f + 1) + break; + } + + n_walked++; + //if (unlikely(n_walked > WRITEBACK_LATENCY) && likely(!wc->writeback_all)) + // break; + + wc->writeback_size++; + list_del(&g->lru); + list_add(&g->lru, &wbl.list); + wbl.size++; + g->write_in_progress = true; + g->wc_list_contiguous = BIO_MAX_PAGES; + f = g; + e->wc_list_contiguous++; + if (unlikely(e->wc_list_contiguous == BIO_MAX_PAGES)) + break; + } + cond_resched(); + } + + if (!list_empty(&skipped)) { + list_splice_tail(&skipped, &wc->lru); + /* + * If we didn't do any progress, we must wait until some + * writeback finishes to avoid burning CPU in a loop + */ + if (unlikely(!wbl.size)) + writecache_wait_for_writeback(wc); + } + + wc_unlock(wc); + + blk_start_plug(&plug); + + if (WC_MODE_PMEM(wc)) + __writecache_writeback_pmem(wc, &wbl); + else + __writecache_writeback_ssd(wc, &wbl); + + blk_finish_plug(&plug); + + if (unlikely(wc->writeback_all)) { + wc_lock(wc); + while (writecache_wait_for_writeback(wc)); + wc_unlock(wc); + } +} + +static int calculate_memory_size(uint64_t device_size, unsigned block_size, + size_t *n_blocks_p, size_t *n_metadata_blocks_p) +{ + uint64_t n_blocks, offset; + struct wc_entry e; + + n_blocks = device_size; + do_div(n_blocks, block_size + sizeof(struct wc_memory_entry)); + + while (1) { + if (!n_blocks) + return -ENOSPC; + /* Verify the following entries[n_blocks] won't overflow */ + if (n_blocks >= ((size_t)-sizeof(struct wc_memory_superblock) / + sizeof(struct wc_memory_entry))) + return -EFBIG; + offset = offsetof(struct wc_memory_superblock, entries[n_blocks]); + offset = (offset + block_size - 1) & ~(uint64_t)(block_size - 1); + if (offset + n_blocks * block_size <= device_size) + break; + n_blocks--; + } + + /* check if the bit field overflows */ + e.index = n_blocks; + if (e.index != n_blocks) + return -EFBIG; + + if (n_blocks_p) + *n_blocks_p = n_blocks; + if (n_metadata_blocks_p) + *n_metadata_blocks_p = offset >> __ffs(block_size); + return 0; +} + +static int init_memory(struct dm_writecache *wc) +{ + size_t b; + int r; + + r = calculate_memory_size(wc->memory_map_size, wc->block_size, &wc->n_blocks, NULL); + if (r) + return r; + + r = writecache_alloc_entries(wc); + if (r) + return r; + + for (b = 0; b < ARRAY_SIZE(sb(wc)->padding); b++) + pmem_assign(sb(wc)->padding[b], cpu_to_le64(0)); + pmem_assign(sb(wc)->version, cpu_to_le32(MEMORY_SUPERBLOCK_VERSION)); + pmem_assign(sb(wc)->block_size, cpu_to_le32(wc->block_size)); + pmem_assign(sb(wc)->n_blocks, cpu_to_le64(wc->n_blocks)); + pmem_assign(sb(wc)->seq_count, cpu_to_le64(0)); + + for (b = 0; b < wc->n_blocks; b++) + write_original_sector_seq_count(wc, &wc->entries[b], -1, -1); + + writecache_flush_all_metadata(wc); + writecache_commit_flushed(wc); + pmem_assign(sb(wc)->magic, cpu_to_le32(MEMORY_SUPERBLOCK_MAGIC)); + writecache_flush_region(wc, &sb(wc)->magic, sizeof sb(wc)->magic); + writecache_commit_flushed(wc); + + return 0; +} + +static void writecache_dtr(struct dm_target *ti) +{ + struct dm_writecache *wc = ti->private; + + if (!wc) + return; + + if (wc->endio_thread) + kthread_stop(wc->endio_thread); + + if (wc->flush_thread) + kthread_stop(wc->flush_thread); + + bioset_exit(&wc->bio_set); + + mempool_exit(&wc->copy_pool); + + if (wc->writeback_wq) + destroy_workqueue(wc->writeback_wq); + + if (wc->dev) + dm_put_device(ti, wc->dev); + + if (wc->ssd_dev) + dm_put_device(ti, wc->ssd_dev); + + if (wc->entries) + vfree(wc->entries); + + if (wc->memory_map) { + if (WC_MODE_PMEM(wc)) + persistent_memory_release(wc); + else + vfree(wc->memory_map); + } + + if (wc->dm_kcopyd) + dm_kcopyd_client_destroy(wc->dm_kcopyd); + + if (wc->dm_io) + dm_io_client_destroy(wc->dm_io); + + if (wc->dirty_bitmap) + vfree(wc->dirty_bitmap); + + kfree(wc); +} + +static int writecache_ctr(struct dm_target *ti, unsigned argc, char **argv) +{ + struct dm_writecache *wc; + struct dm_arg_set as; + const char *string; + unsigned opt_params; + size_t offset, data_size; + int i, r; + char dummy; + int high_wm_percent = HIGH_WATERMARK; + int low_wm_percent = LOW_WATERMARK; + uint64_t x; + struct wc_memory_superblock s; + + static struct dm_arg _args[] = { + {0, 10, "Invalid number of feature args"}, + }; + + as.argc = argc; + as.argv = argv; + + wc = kzalloc(sizeof(struct dm_writecache), GFP_KERNEL); + if (!wc) { + ti->error = "Cannot allocate writecache structure"; + r = -ENOMEM; + goto bad; + } + ti->private = wc; + wc->ti = ti; + + mutex_init(&wc->lock); + writecache_poison_lists(wc); + init_waitqueue_head(&wc->freelist_wait); + timer_setup(&wc->autocommit_timer, writecache_autocommit_timer, 0); + + for (i = 0; i < 2; i++) { + atomic_set(&wc->bio_in_progress[i], 0); + init_waitqueue_head(&wc->bio_in_progress_wait[i]); + } + + wc->dm_io = dm_io_client_create(); + if (IS_ERR(wc->dm_io)) { + r = PTR_ERR(wc->dm_io); + ti->error = "Unable to allocate dm-io client"; + wc->dm_io = NULL; + goto bad; + } + + wc->writeback_wq = alloc_workqueue("writecache-writeabck", WQ_MEM_RECLAIM, 1); + if (!wc->writeback_wq) { + r = -ENOMEM; + ti->error = "Could not allocate writeback workqueue"; + goto bad; + } + INIT_WORK(&wc->writeback_work, writecache_writeback); + INIT_WORK(&wc->flush_work, writecache_flush_work); + + raw_spin_lock_init(&wc->endio_list_lock); + INIT_LIST_HEAD(&wc->endio_list); + wc->endio_thread = kthread_create(writecache_endio_thread, wc, "writecache_endio"); + if (IS_ERR(wc->endio_thread)) { + r = PTR_ERR(wc->endio_thread); + wc->endio_thread = NULL; + ti->error = "Couldn't spawn endio thread"; + goto bad; + } + wake_up_process(wc->endio_thread); + + /* + * Parse the mode (pmem or ssd) + */ + string = dm_shift_arg(&as); + if (!string) + goto bad_arguments; + + if (!strcasecmp(string, "s")) { + wc->pmem_mode = false; + } else if (!strcasecmp(string, "p")) { +#ifdef DM_WRITECACHE_HAS_PMEM + wc->pmem_mode = true; + wc->writeback_fua = true; +#else + /* + * If the architecture doesn't support persistent memory or + * the kernel doesn't support any DAX drivers, this driver can + * only be used in SSD-only mode. + */ + r = -EOPNOTSUPP; + ti->error = "Persistent memory or DAX not supported on this system"; + goto bad; +#endif + } else { + goto bad_arguments; + } + + if (WC_MODE_PMEM(wc)) { + r = bioset_init(&wc->bio_set, BIO_POOL_SIZE, + offsetof(struct writeback_struct, bio), + BIOSET_NEED_BVECS); + if (r) { + ti->error = "Could not allocate bio set"; + goto bad; + } + } else { + r = mempool_init_kmalloc_pool(&wc->copy_pool, 1, sizeof(struct copy_struct)); + if (r) { + ti->error = "Could not allocate mempool"; + goto bad; + } + } + + /* + * Parse the origin data device + */ + string = dm_shift_arg(&as); + if (!string) + goto bad_arguments; + r = dm_get_device(ti, string, dm_table_get_mode(ti->table), &wc->dev); + if (r) { + ti->error = "Origin data device lookup failed"; + goto bad; + } + + /* + * Parse cache data device (be it pmem or ssd) + */ + string = dm_shift_arg(&as); + if (!string) + goto bad_arguments; + + r = dm_get_device(ti, string, dm_table_get_mode(ti->table), &wc->ssd_dev); + if (r) { + ti->error = "Cache data device lookup failed"; + goto bad; + } + wc->memory_map_size = i_size_read(wc->ssd_dev->bdev->bd_inode); + + if (WC_MODE_PMEM(wc)) { + r = persistent_memory_claim(wc); + if (r) { + ti->error = "Unable to map persistent memory for cache"; + goto bad; + } + } + + /* + * Parse the cache block size + */ + string = dm_shift_arg(&as); + if (!string) + goto bad_arguments; + if (sscanf(string, "%u%c", &wc->block_size, &dummy) != 1 || + wc->block_size < 512 || wc->block_size > PAGE_SIZE || + (wc->block_size & (wc->block_size - 1))) { + r = -EINVAL; + ti->error = "Invalid block size"; + goto bad; + } + wc->block_size_bits = __ffs(wc->block_size); + + wc->max_writeback_jobs = MAX_WRITEBACK_JOBS; + wc->autocommit_blocks = !WC_MODE_PMEM(wc) ? AUTOCOMMIT_BLOCKS_SSD : AUTOCOMMIT_BLOCKS_PMEM; + wc->autocommit_jiffies = msecs_to_jiffies(AUTOCOMMIT_MSEC); + + /* + * Parse optional arguments + */ + r = dm_read_arg_group(_args, &as, &opt_params, &ti->error); + if (r) + goto bad; + + while (opt_params) { + string = dm_shift_arg(&as), opt_params--; + if (!strcasecmp(string, "high_watermark") && opt_params >= 1) { + string = dm_shift_arg(&as), opt_params--; + if (sscanf(string, "%d%c", &high_wm_percent, &dummy) != 1) + goto invalid_optional; + if (high_wm_percent < 0 || high_wm_percent > 100) + goto invalid_optional; + wc->high_wm_percent_set = true; + } else if (!strcasecmp(string, "low_watermark") && opt_params >= 1) { + string = dm_shift_arg(&as), opt_params--; + if (sscanf(string, "%d%c", &low_wm_percent, &dummy) != 1) + goto invalid_optional; + if (low_wm_percent < 0 || low_wm_percent > 100) + goto invalid_optional; + wc->low_wm_percent_set = true; + } else if (!strcasecmp(string, "writeback_jobs") && opt_params >= 1) { + string = dm_shift_arg(&as), opt_params--; + if (sscanf(string, "%u%c", &wc->max_writeback_jobs, &dummy) != 1) + goto invalid_optional; + wc->max_writeback_jobs_set = true; + } else if (!strcasecmp(string, "autocommit_blocks") && opt_params >= 1) { + string = dm_shift_arg(&as), opt_params--; + if (sscanf(string, "%u%c", &wc->autocommit_blocks, &dummy) != 1) + goto invalid_optional; + wc->autocommit_blocks_set = true; + } else if (!strcasecmp(string, "autocommit_time") && opt_params >= 1) { + unsigned autocommit_msecs; + string = dm_shift_arg(&as), opt_params--; + if (sscanf(string, "%u%c", &autocommit_msecs, &dummy) != 1) + goto invalid_optional; + if (autocommit_msecs > 3600000) + goto invalid_optional; + wc->autocommit_jiffies = msecs_to_jiffies(autocommit_msecs); + wc->autocommit_time_set = true; + } else if (!strcasecmp(string, "fua")) { + if (WC_MODE_PMEM(wc)) { + wc->writeback_fua = true; + wc->writeback_fua_set = true; + } else goto invalid_optional; + } else if (!strcasecmp(string, "nofua")) { + if (WC_MODE_PMEM(wc)) { + wc->writeback_fua = false; + wc->writeback_fua_set = true; + } else goto invalid_optional; + } else { +invalid_optional: + r = -EINVAL; + ti->error = "Invalid optional argument"; + goto bad; + } + } + + if (high_wm_percent < low_wm_percent) { + r = -EINVAL; + ti->error = "High watermark must be greater than or equal to low watermark"; + goto bad; + } + + if (!WC_MODE_PMEM(wc)) { + struct dm_io_region region; + struct dm_io_request req; + size_t n_blocks, n_metadata_blocks; + uint64_t n_bitmap_bits; + + bio_list_init(&wc->flush_list); + wc->flush_thread = kthread_create(writecache_flush_thread, wc, "dm_writecache_flush"); + if (IS_ERR(wc->flush_thread)) { + r = PTR_ERR(wc->flush_thread); + wc->flush_thread = NULL; + ti->error = "Couldn't spawn endio thread"; + goto bad; + } + wake_up_process(wc->flush_thread); + + r = calculate_memory_size(wc->memory_map_size, wc->block_size, + &n_blocks, &n_metadata_blocks); + if (r) { + ti->error = "Invalid device size"; + goto bad; + } + + n_bitmap_bits = (((uint64_t)n_metadata_blocks << wc->block_size_bits) + + BITMAP_GRANULARITY - 1) / BITMAP_GRANULARITY; + /* this is limitation of test_bit functions */ + if (n_bitmap_bits > 1U << 31) { + r = -EFBIG; + ti->error = "Invalid device size"; + goto bad; + } + + wc->memory_map = vmalloc(n_metadata_blocks << wc->block_size_bits); + if (!wc->memory_map) { + r = -ENOMEM; + ti->error = "Unable to allocate memory for metadata"; + goto bad; + } + + wc->dm_kcopyd = dm_kcopyd_client_create(&dm_kcopyd_throttle); + if (IS_ERR(wc->dm_kcopyd)) { + r = PTR_ERR(wc->dm_kcopyd); + ti->error = "Unable to allocate dm-kcopyd client"; + wc->dm_kcopyd = NULL; + goto bad; + } + + wc->metadata_sectors = n_metadata_blocks << (wc->block_size_bits - SECTOR_SHIFT); + wc->dirty_bitmap_size = (n_bitmap_bits + BITS_PER_LONG - 1) / + BITS_PER_LONG * sizeof(unsigned long); + wc->dirty_bitmap = vzalloc(wc->dirty_bitmap_size); + if (!wc->dirty_bitmap) { + r = -ENOMEM; + ti->error = "Unable to allocate dirty bitmap"; + goto bad; + } + + region.bdev = wc->ssd_dev->bdev; + region.sector = 0; + region.count = wc->metadata_sectors; + req.bi_op = REQ_OP_READ; + req.bi_op_flags = REQ_SYNC; + req.mem.type = DM_IO_VMA; + req.mem.ptr.vma = (char *)wc->memory_map; + req.client = wc->dm_io; + req.notify.fn = NULL; + + r = dm_io(&req, 1, ®ion, NULL); + if (r) { + ti->error = "Unable to read metadata"; + goto bad; + } + } + + r = memcpy_mcsafe(&s, sb(wc), sizeof(struct wc_memory_superblock)); + if (r) { + ti->error = "Hardware memory error when reading superblock"; + goto bad; + } + if (!le32_to_cpu(s.magic) && !le32_to_cpu(s.version)) { + r = init_memory(wc); + if (r) { + ti->error = "Unable to initialize device"; + goto bad; + } + r = memcpy_mcsafe(&s, sb(wc), sizeof(struct wc_memory_superblock)); + if (r) { + ti->error = "Hardware memory error when reading superblock"; + goto bad; + } + } + + if (le32_to_cpu(s.magic) != MEMORY_SUPERBLOCK_MAGIC) { + ti->error = "Invalid magic in the superblock"; + r = -EINVAL; + goto bad; + } + + if (le32_to_cpu(s.version) != MEMORY_SUPERBLOCK_VERSION) { + ti->error = "Invalid version in the superblock"; + r = -EINVAL; + goto bad; + } + + if (le32_to_cpu(s.block_size) != wc->block_size) { + ti->error = "Block size does not match superblock"; + r = -EINVAL; + goto bad; + } + + wc->n_blocks = le64_to_cpu(s.n_blocks); + + offset = wc->n_blocks * sizeof(struct wc_memory_entry); + if (offset / sizeof(struct wc_memory_entry) != le64_to_cpu(sb(wc)->n_blocks)) { +overflow: + ti->error = "Overflow in size calculation"; + r = -EINVAL; + goto bad; + } + offset += sizeof(struct wc_memory_superblock); + if (offset < sizeof(struct wc_memory_superblock)) + goto overflow; + offset = (offset + wc->block_size - 1) & ~(size_t)(wc->block_size - 1); + data_size = wc->n_blocks * (size_t)wc->block_size; + if (!offset || (data_size / wc->block_size != wc->n_blocks) || + (offset + data_size < offset)) + goto overflow; + if (offset + data_size > wc->memory_map_size) { + ti->error = "Memory area is too small"; + r = -EINVAL; + goto bad; + } + + wc->metadata_sectors = offset >> SECTOR_SHIFT; + wc->block_start = (char *)sb(wc) + offset; + + x = (uint64_t)wc->n_blocks * (100 - high_wm_percent); + x += 50; + do_div(x, 100); + wc->freelist_high_watermark = x; + x = (uint64_t)wc->n_blocks * (100 - low_wm_percent); + x += 50; + do_div(x, 100); + wc->freelist_low_watermark = x; + + r = writecache_alloc_entries(wc); + if (r) { + ti->error = "Cannot allocate memory"; + goto bad; + } + + ti->num_flush_bios = 1; + ti->flush_supported = true; + ti->num_discard_bios = 1; + + if (WC_MODE_PMEM(wc)) + persistent_memory_flush_cache(wc->memory_map, wc->memory_map_size); + + return 0; + +bad_arguments: + r = -EINVAL; + ti->error = "Bad arguments"; +bad: + writecache_dtr(ti); + return r; +} + +static void writecache_status(struct dm_target *ti, status_type_t type, + unsigned status_flags, char *result, unsigned maxlen) +{ + struct dm_writecache *wc = ti->private; + unsigned extra_args; + unsigned sz = 0; + uint64_t x; + + switch (type) { + case STATUSTYPE_INFO: + DMEMIT("%ld %llu %llu %llu", writecache_has_error(wc), + (unsigned long long)wc->n_blocks, (unsigned long long)wc->freelist_size, + (unsigned long long)wc->writeback_size); + break; + case STATUSTYPE_TABLE: + DMEMIT("%c %s %s %u ", WC_MODE_PMEM(wc) ? 'p' : 's', + wc->dev->name, wc->ssd_dev->name, wc->block_size); + extra_args = 0; + if (wc->high_wm_percent_set) + extra_args += 2; + if (wc->low_wm_percent_set) + extra_args += 2; + if (wc->max_writeback_jobs_set) + extra_args += 2; + if (wc->autocommit_blocks_set) + extra_args += 2; + if (wc->autocommit_time_set) + extra_args += 2; + if (wc->writeback_fua_set) + extra_args++; + + DMEMIT("%u", extra_args); + if (wc->high_wm_percent_set) { + x = (uint64_t)wc->freelist_high_watermark * 100; + x += wc->n_blocks / 2; + do_div(x, (size_t)wc->n_blocks); + DMEMIT(" high_watermark %u", 100 - (unsigned)x); + } + if (wc->low_wm_percent_set) { + x = (uint64_t)wc->freelist_low_watermark * 100; + x += wc->n_blocks / 2; + do_div(x, (size_t)wc->n_blocks); + DMEMIT(" low_watermark %u", 100 - (unsigned)x); + } + if (wc->max_writeback_jobs_set) + DMEMIT(" writeback_jobs %u", wc->max_writeback_jobs); + if (wc->autocommit_blocks_set) + DMEMIT(" autocommit_blocks %u", wc->autocommit_blocks); + if (wc->autocommit_time_set) + DMEMIT(" autocommit_time %u", jiffies_to_msecs(wc->autocommit_jiffies)); + if (wc->writeback_fua_set) + DMEMIT(" %sfua", wc->writeback_fua ? "" : "no"); + break; + } +} + +static struct target_type writecache_target = { + .name = "writecache", + .version = {1, 0, 0}, + .module = THIS_MODULE, + .ctr = writecache_ctr, + .dtr = writecache_dtr, + .status = writecache_status, + .postsuspend = writecache_suspend, + .resume = writecache_resume, + .message = writecache_message, + .map = writecache_map, + .end_io = writecache_end_io, + .iterate_devices = writecache_iterate_devices, + .io_hints = writecache_io_hints, +}; + +static int __init dm_writecache_init(void) +{ + int r; + + r = dm_register_target(&writecache_target); + if (r < 0) { + DMERR("register failed %d", r); + return r; + } + + return 0; +} + +static void __exit dm_writecache_exit(void) +{ + dm_unregister_target(&writecache_target); +} + +module_init(dm_writecache_init); +module_exit(dm_writecache_exit); + +MODULE_DESCRIPTION(DM_NAME " writecache target"); +MODULE_AUTHOR("Mikulas Patocka <dm-devel@redhat.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/md/dm-zoned-target.c b/drivers/md/dm-zoned-target.c index 30602d15ad9a..3c0e45f4dcf5 100644 --- a/drivers/md/dm-zoned-target.c +++ b/drivers/md/dm-zoned-target.c @@ -52,9 +52,9 @@ struct dmz_target { struct dmz_reclaim *reclaim; /* For chunk work */ - struct mutex chunk_lock; struct radix_tree_root chunk_rxtree; struct workqueue_struct *chunk_wq; + struct mutex chunk_lock; /* For cloned BIOs to zones */ struct bio_set bio_set; diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c index 239c7bb3929b..f983c3fdf204 100644 --- a/drivers/md/md-bitmap.c +++ b/drivers/md/md-bitmap.c @@ -789,8 +789,8 @@ static int bitmap_storage_alloc(struct bitmap_storage *store, num_pages = DIV_ROUND_UP(bytes, PAGE_SIZE); offset = slot_number * num_pages; - store->filemap = kmalloc(sizeof(struct page *) - * num_pages, GFP_KERNEL); + store->filemap = kmalloc_array(num_pages, sizeof(struct page *), + GFP_KERNEL); if (!store->filemap) return -ENOMEM; @@ -2117,7 +2117,7 @@ int bitmap_resize(struct bitmap *bitmap, sector_t blocks, pages = DIV_ROUND_UP(chunks, PAGE_COUNTER_RATIO); - new_bp = kzalloc(pages * sizeof(*new_bp), GFP_KERNEL); + new_bp = kcalloc(pages, sizeof(*new_bp), GFP_KERNEL); ret = -ENOMEM; if (!new_bp) { bitmap_file_unmap(&store); diff --git a/drivers/md/md-cluster.c b/drivers/md/md-cluster.c index 79bfbc840385..021cbf9ef1bf 100644 --- a/drivers/md/md-cluster.c +++ b/drivers/md/md-cluster.c @@ -1380,9 +1380,9 @@ static int lock_all_bitmaps(struct mddev *mddev) char str[64]; struct md_cluster_info *cinfo = mddev->cluster_info; - cinfo->other_bitmap_lockres = kzalloc((mddev->bitmap_info.nodes - 1) * - sizeof(struct dlm_lock_resource *), - GFP_KERNEL); + cinfo->other_bitmap_lockres = + kcalloc(mddev->bitmap_info.nodes - 1, + sizeof(struct dlm_lock_resource *), GFP_KERNEL); if (!cinfo->other_bitmap_lockres) { pr_err("md: can't alloc mem for other bitmap locks\n"); return 0; diff --git a/drivers/md/md-multipath.c b/drivers/md/md-multipath.c index f71fcdb9b39c..881487de1e25 100644 --- a/drivers/md/md-multipath.c +++ b/drivers/md/md-multipath.c @@ -399,7 +399,8 @@ static int multipath_run (struct mddev *mddev) if (!conf) goto out; - conf->multipaths = kzalloc(sizeof(struct multipath_info)*mddev->raid_disks, + conf->multipaths = kcalloc(mddev->raid_disks, + sizeof(struct multipath_info), GFP_KERNEL); if (!conf->multipaths) goto out_free_conf; diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index 65ae47a02218..ac1cffd2a09b 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -159,12 +159,14 @@ static int create_strip_zones(struct mddev *mddev, struct r0conf **private_conf) } err = -ENOMEM; - conf->strip_zone = kzalloc(sizeof(struct strip_zone)* - conf->nr_strip_zones, GFP_KERNEL); + conf->strip_zone = kcalloc(conf->nr_strip_zones, + sizeof(struct strip_zone), + GFP_KERNEL); if (!conf->strip_zone) goto abort; - conf->devlist = kzalloc(sizeof(struct md_rdev*)* - conf->nr_strip_zones*mddev->raid_disks, + conf->devlist = kzalloc(array3_size(sizeof(struct md_rdev *), + conf->nr_strip_zones, + mddev->raid_disks), GFP_KERNEL); if (!conf->devlist) goto abort; diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 0b344d087581..8e05c1092aef 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -126,8 +126,8 @@ static void * r1buf_pool_alloc(gfp_t gfp_flags, void *data) if (!r1_bio) return NULL; - rps = kmalloc(sizeof(struct resync_pages) * pi->raid_disks, - gfp_flags); + rps = kmalloc_array(pi->raid_disks, sizeof(struct resync_pages), + gfp_flags); if (!rps) goto out_free_r1bio; @@ -2936,9 +2936,9 @@ static struct r1conf *setup_conf(struct mddev *mddev) if (!conf->barrier) goto abort; - conf->mirrors = kzalloc(sizeof(struct raid1_info) - * mddev->raid_disks * 2, - GFP_KERNEL); + conf->mirrors = kzalloc(array3_size(sizeof(struct raid1_info), + mddev->raid_disks, 2), + GFP_KERNEL); if (!conf->mirrors) goto abort; @@ -3241,7 +3241,8 @@ static int raid1_reshape(struct mddev *mddev) kfree(newpoolinfo); return ret; } - newmirrors = kzalloc(sizeof(struct raid1_info) * raid_disks * 2, + newmirrors = kzalloc(array3_size(sizeof(struct raid1_info), + raid_disks, 2), GFP_KERNEL); if (!newmirrors) { kfree(newpoolinfo); diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 1147ae59e3b6..478cf446827f 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -175,7 +175,7 @@ static void * r10buf_pool_alloc(gfp_t gfp_flags, void *data) nalloc_rp = nalloc; else nalloc_rp = nalloc * 2; - rps = kmalloc(sizeof(struct resync_pages) * nalloc_rp, gfp_flags); + rps = kmalloc_array(nalloc_rp, sizeof(struct resync_pages), gfp_flags); if (!rps) goto out_free_r10bio; @@ -3688,8 +3688,8 @@ static struct r10conf *setup_conf(struct mddev *mddev) goto out; /* FIXME calc properly */ - conf->mirrors = kzalloc(sizeof(struct raid10_info)*(mddev->raid_disks + - max(0,-mddev->delta_disks)), + conf->mirrors = kcalloc(mddev->raid_disks + max(0, -mddev->delta_disks), + sizeof(struct raid10_info), GFP_KERNEL); if (!conf->mirrors) goto out; @@ -4129,11 +4129,10 @@ static int raid10_check_reshape(struct mddev *mddev) conf->mirrors_new = NULL; if (mddev->delta_disks > 0) { /* allocate new 'mirrors' list */ - conf->mirrors_new = kzalloc( - sizeof(struct raid10_info) - *(mddev->raid_disks + - mddev->delta_disks), - GFP_KERNEL); + conf->mirrors_new = + kcalloc(mddev->raid_disks + mddev->delta_disks, + sizeof(struct raid10_info), + GFP_KERNEL); if (!conf->mirrors_new) return -ENOMEM; } diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 73489446bbcb..2031506a0ecd 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -2396,7 +2396,7 @@ static int resize_stripes(struct r5conf *conf, int newsize) * is completely stalled, so now is a good time to resize * conf->disks and the scribble region */ - ndisks = kzalloc(newsize * sizeof(struct disk_info), GFP_NOIO); + ndisks = kcalloc(newsize, sizeof(struct disk_info), GFP_NOIO); if (ndisks) { for (i = 0; i < conf->pool_size; i++) ndisks[i] = conf->disks[i]; @@ -6664,9 +6664,9 @@ static int alloc_thread_groups(struct r5conf *conf, int cnt, } *group_cnt = num_possible_nodes(); size = sizeof(struct r5worker) * cnt; - workers = kzalloc(size * *group_cnt, GFP_NOIO); - *worker_groups = kzalloc(sizeof(struct r5worker_group) * - *group_cnt, GFP_NOIO); + workers = kcalloc(size, *group_cnt, GFP_NOIO); + *worker_groups = kcalloc(*group_cnt, sizeof(struct r5worker_group), + GFP_NOIO); if (!*worker_groups || !workers) { kfree(workers); kfree(*worker_groups); @@ -6894,8 +6894,9 @@ static struct r5conf *setup_conf(struct mddev *mddev) goto abort; INIT_LIST_HEAD(&conf->free_list); INIT_LIST_HEAD(&conf->pending_list); - conf->pending_data = kzalloc(sizeof(struct r5pending_data) * - PENDING_IO_MAX, GFP_KERNEL); + conf->pending_data = kcalloc(PENDING_IO_MAX, + sizeof(struct r5pending_data), + GFP_KERNEL); if (!conf->pending_data) goto abort; for (i = 0; i < PENDING_IO_MAX; i++) @@ -6944,7 +6945,7 @@ static struct r5conf *setup_conf(struct mddev *mddev) conf->previous_raid_disks = mddev->raid_disks - mddev->delta_disks; max_disks = max(conf->raid_disks, conf->previous_raid_disks); - conf->disks = kzalloc(max_disks * sizeof(struct disk_info), + conf->disks = kcalloc(max_disks, sizeof(struct disk_info), GFP_KERNEL); if (!conf->disks) diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c index 9b64f4f354bf..abd4c788dffd 100644 --- a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c +++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c @@ -119,12 +119,14 @@ int tpg_alloc(struct tpg_data *tpg, unsigned max_w) for (plane = 0; plane < TPG_MAX_PLANES; plane++) { unsigned pixelsz = plane ? 2 : 4; - tpg->lines[pat][plane] = vzalloc(max_w * 2 * pixelsz); + tpg->lines[pat][plane] = + vzalloc(array3_size(max_w, 2, pixelsz)); if (!tpg->lines[pat][plane]) return -ENOMEM; if (plane == 0) continue; - tpg->downsampled_lines[pat][plane] = vzalloc(max_w * 2 * pixelsz); + tpg->downsampled_lines[pat][plane] = + vzalloc(array3_size(max_w, 2, pixelsz)); if (!tpg->downsampled_lines[pat][plane]) return -ENOMEM; } @@ -132,13 +134,16 @@ int tpg_alloc(struct tpg_data *tpg, unsigned max_w) for (plane = 0; plane < TPG_MAX_PLANES; plane++) { unsigned pixelsz = plane ? 2 : 4; - tpg->contrast_line[plane] = vzalloc(max_w * pixelsz); + tpg->contrast_line[plane] = + vzalloc(array_size(pixelsz, max_w)); if (!tpg->contrast_line[plane]) return -ENOMEM; - tpg->black_line[plane] = vzalloc(max_w * pixelsz); + tpg->black_line[plane] = + vzalloc(array_size(pixelsz, max_w)); if (!tpg->black_line[plane]) return -ENOMEM; - tpg->random_line[plane] = vzalloc(max_w * 2 * pixelsz); + tpg->random_line[plane] = + vzalloc(array3_size(max_w, 2, pixelsz)); if (!tpg->random_line[plane]) return -ENOMEM; } diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c index cb078d688c70..d548f98c7a67 100644 --- a/drivers/media/dvb-core/dmxdev.c +++ b/drivers/media/dvb-core/dmxdev.c @@ -1417,7 +1417,8 @@ int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter) if (dmxdev->demux->open(dmxdev->demux) < 0) return -EUSERS; - dmxdev->filter = vmalloc(dmxdev->filternum * sizeof(struct dmxdev_filter)); + dmxdev->filter = vmalloc(array_size(sizeof(struct dmxdev_filter), + dmxdev->filternum)); if (!dmxdev->filter) return -ENOMEM; diff --git a/drivers/media/dvb-core/dvb_demux.c b/drivers/media/dvb-core/dvb_demux.c index f45091246bdc..39a2c6ccf31d 100644 --- a/drivers/media/dvb-core/dvb_demux.c +++ b/drivers/media/dvb-core/dvb_demux.c @@ -1247,12 +1247,14 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux) dvbdemux->cnt_storage = NULL; dvbdemux->users = 0; - dvbdemux->filter = vmalloc(dvbdemux->filternum * sizeof(struct dvb_demux_filter)); + dvbdemux->filter = vmalloc(array_size(sizeof(struct dvb_demux_filter), + dvbdemux->filternum)); if (!dvbdemux->filter) return -ENOMEM; - dvbdemux->feed = vmalloc(dvbdemux->feednum * sizeof(struct dvb_demux_feed)); + dvbdemux->feed = vmalloc(array_size(sizeof(struct dvb_demux_feed), + dvbdemux->feednum)); if (!dvbdemux->feed) { vfree(dvbdemux->filter); dvbdemux->filter = NULL; diff --git a/drivers/media/dvb-frontends/dib7000p.c b/drivers/media/dvb-frontends/dib7000p.c index 902af482448e..5a8dbc0b25fb 100644 --- a/drivers/media/dvb-frontends/dib7000p.c +++ b/drivers/media/dvb-frontends/dib7000p.c @@ -2018,10 +2018,10 @@ static int dib7000pc_detection(struct i2c_adapter *i2c_adap) }; int ret = 0; - tx = kzalloc(2*sizeof(u8), GFP_KERNEL); + tx = kzalloc(2, GFP_KERNEL); if (!tx) return -ENOMEM; - rx = kzalloc(2*sizeof(u8), GFP_KERNEL); + rx = kzalloc(2, GFP_KERNEL); if (!rx) { ret = -ENOMEM; goto rx_memory_error; diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c index 6f35173d2968..22eec8f65485 100644 --- a/drivers/media/dvb-frontends/dib8000.c +++ b/drivers/media/dvb-frontends/dib8000.c @@ -4271,12 +4271,12 @@ static int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 new_addr = 0; struct i2c_device client = {.adap = host }; - client.i2c_write_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL); + client.i2c_write_buffer = kzalloc(4, GFP_KERNEL); if (!client.i2c_write_buffer) { dprintk("%s: not enough memory\n", __func__); return -ENOMEM; } - client.i2c_read_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL); + client.i2c_read_buffer = kzalloc(4, GFP_KERNEL); if (!client.i2c_read_buffer) { dprintk("%s: not enough memory\n", __func__); ret = -ENOMEM; diff --git a/drivers/media/dvb-frontends/dib9000.c b/drivers/media/dvb-frontends/dib9000.c index f9289f488de7..b8edb55696bb 100644 --- a/drivers/media/dvb-frontends/dib9000.c +++ b/drivers/media/dvb-frontends/dib9000.c @@ -2381,12 +2381,12 @@ int dib9000_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defaul u8 new_addr = 0; struct i2c_device client = {.i2c_adap = i2c }; - client.i2c_write_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL); + client.i2c_write_buffer = kzalloc(4, GFP_KERNEL); if (!client.i2c_write_buffer) { dprintk("%s: not enough memory\n", __func__); return -ENOMEM; } - client.i2c_read_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL); + client.i2c_read_buffer = kzalloc(4, GFP_KERNEL); if (!client.i2c_read_buffer) { dprintk("%s: not enough memory\n", __func__); ret = -ENOMEM; diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c index ff46d2c96cea..5007c9659342 100644 --- a/drivers/media/i2c/s5k5baf.c +++ b/drivers/media/i2c/s5k5baf.c @@ -373,7 +373,7 @@ static int s5k5baf_fw_parse(struct device *dev, struct s5k5baf_fw **fw, data += S5K5BAG_FW_TAG_LEN; count -= S5K5BAG_FW_TAG_LEN; - d = devm_kzalloc(dev, count * sizeof(u16), GFP_KERNEL); + d = devm_kcalloc(dev, count, sizeof(u16), GFP_KERNEL); if (!d) return -ENOMEM; diff --git a/drivers/media/pci/bt8xx/bttv-risc.c b/drivers/media/pci/bt8xx/bttv-risc.c index 6a6be0b49f70..74aff6877d9c 100644 --- a/drivers/media/pci/bt8xx/bttv-risc.c +++ b/drivers/media/pci/bt8xx/bttv-risc.c @@ -256,7 +256,8 @@ bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc, u32 addr; /* skip list for window clipping */ - if (NULL == (skips = kmalloc(sizeof(*skips) * ov->nclips,GFP_KERNEL))) + skips = kmalloc_array(ov->nclips, sizeof(*skips),GFP_KERNEL); + if (NULL == skips) return -ENOMEM; /* estimate risc mem: worst case is (1.5*clip+1) * lines instructions diff --git a/drivers/media/pci/cx23885/cx23885-alsa.c b/drivers/media/pci/cx23885/cx23885-alsa.c index 20b3cb17f97f..db1e8ff35474 100644 --- a/drivers/media/pci/cx23885/cx23885-alsa.c +++ b/drivers/media/pci/cx23885/cx23885-alsa.c @@ -95,7 +95,7 @@ static int cx23885_alsa_dma_init(struct cx23885_audio_dev *chip, int nr_pages) memset(buf->vaddr, 0, nr_pages << PAGE_SHIFT); buf->nr_pages = nr_pages; - buf->sglist = vzalloc(buf->nr_pages * sizeof(*buf->sglist)); + buf->sglist = vzalloc(array_size(sizeof(*buf->sglist), buf->nr_pages)); if (NULL == buf->sglist) goto vzalloc_err; diff --git a/drivers/media/pci/cx25821/cx25821-alsa.c b/drivers/media/pci/cx25821/cx25821-alsa.c index a45bf0331eeb..ef6380651c10 100644 --- a/drivers/media/pci/cx25821/cx25821-alsa.c +++ b/drivers/media/pci/cx25821/cx25821-alsa.c @@ -159,7 +159,7 @@ static int cx25821_alsa_dma_init(struct cx25821_audio_dev *chip, int nr_pages) memset(buf->vaddr, 0, nr_pages << PAGE_SHIFT); buf->nr_pages = nr_pages; - buf->sglist = vzalloc(buf->nr_pages * sizeof(*buf->sglist)); + buf->sglist = vzalloc(array_size(sizeof(*buf->sglist), buf->nr_pages)); if (NULL == buf->sglist) goto vzalloc_err; diff --git a/drivers/media/pci/cx88/cx88-alsa.c b/drivers/media/pci/cx88/cx88-alsa.c index 8a28fda703a2..e5c3387cd1e8 100644 --- a/drivers/media/pci/cx88/cx88-alsa.c +++ b/drivers/media/pci/cx88/cx88-alsa.c @@ -298,7 +298,7 @@ static int cx88_alsa_dma_init(struct cx88_audio_dev *chip, int nr_pages) memset(buf->vaddr, 0, nr_pages << PAGE_SHIFT); buf->nr_pages = nr_pages; - buf->sglist = vzalloc(buf->nr_pages * sizeof(*buf->sglist)); + buf->sglist = vzalloc(array_size(sizeof(*buf->sglist), buf->nr_pages)); if (!buf->sglist) goto vzalloc_err; diff --git a/drivers/media/pci/ivtv/ivtvfb.c b/drivers/media/pci/ivtv/ivtvfb.c index 8e62b8be6529..b19058e36853 100644 --- a/drivers/media/pci/ivtv/ivtvfb.c +++ b/drivers/media/pci/ivtv/ivtvfb.c @@ -1077,7 +1077,7 @@ static int ivtvfb_init_vidmode(struct ivtv *itv) /* Allocate the pseudo palette */ oi->ivtvfb_info.pseudo_palette = - kmalloc(sizeof(u32) * 16, GFP_KERNEL|__GFP_NOWARN); + kmalloc_array(16, sizeof(u32), GFP_KERNEL|__GFP_NOWARN); if (!oi->ivtvfb_info.pseudo_palette) { IVTVFB_ERR("abort, unable to alloc pseudo palette\n"); diff --git a/drivers/media/pci/meye/meye.c b/drivers/media/pci/meye/meye.c index dedcdb573427..8001d3e9134e 100644 --- a/drivers/media/pci/meye/meye.c +++ b/drivers/media/pci/meye/meye.c @@ -1625,7 +1625,7 @@ static int meye_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) ret = -ENOMEM; meye.mchip_dev = pcidev; - meye.grab_temp = vmalloc(MCHIP_NB_PAGES_MJPEG * PAGE_SIZE); + meye.grab_temp = vmalloc(array_size(PAGE_SIZE, MCHIP_NB_PAGES_MJPEG)); if (!meye.grab_temp) goto outvmalloc; diff --git a/drivers/media/pci/pt1/pt1.c b/drivers/media/pci/pt1/pt1.c index 5708f69622cc..fda969a85684 100644 --- a/drivers/media/pci/pt1/pt1.c +++ b/drivers/media/pci/pt1/pt1.c @@ -615,7 +615,7 @@ static int pt1_init_tables(struct pt1 *pt1) if (!pt1_nr_tables) return 0; - tables = vmalloc(sizeof(struct pt1_table) * pt1_nr_tables); + tables = vmalloc(array_size(pt1_nr_tables, sizeof(struct pt1_table))); if (tables == NULL) return -ENOMEM; diff --git a/drivers/media/pci/saa7134/saa7134-alsa.c b/drivers/media/pci/saa7134/saa7134-alsa.c index 72311445d13d..b90cfde6e301 100644 --- a/drivers/media/pci/saa7134/saa7134-alsa.c +++ b/drivers/media/pci/saa7134/saa7134-alsa.c @@ -279,7 +279,7 @@ static int saa7134_alsa_dma_init(struct saa7134_dev *dev, int nr_pages) memset(dma->vaddr, 0, nr_pages << PAGE_SHIFT); dma->nr_pages = nr_pages; - dma->sglist = vzalloc(dma->nr_pages * sizeof(*dma->sglist)); + dma->sglist = vzalloc(array_size(sizeof(*dma->sglist), dma->nr_pages)); if (NULL == dma->sglist) goto vzalloc_err; diff --git a/drivers/media/pci/ttpci/av7110_ipack.c b/drivers/media/pci/ttpci/av7110_ipack.c index 5aff26574fe1..ec528fae7333 100644 --- a/drivers/media/pci/ttpci/av7110_ipack.c +++ b/drivers/media/pci/ttpci/av7110_ipack.c @@ -24,7 +24,7 @@ void av7110_ipack_reset(struct ipack *p) int av7110_ipack_init(struct ipack *p, int size, void (*func)(u8 *buf, int size, void *priv)) { - if (!(p->buf = vmalloc(size*sizeof(u8)))) { + if (!(p->buf = vmalloc(size))) { printk(KERN_WARNING "Couldn't allocate memory for ipack\n"); return -ENOMEM; } diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c index 58ebc2220d0e..b05738a95e55 100644 --- a/drivers/media/platform/am437x/am437x-vpfe.c +++ b/drivers/media/platform/am437x/am437x-vpfe.c @@ -2586,8 +2586,10 @@ static int vpfe_probe(struct platform_device *pdev) pm_runtime_put_sync(&pdev->dev); - vpfe->sd = devm_kzalloc(&pdev->dev, sizeof(struct v4l2_subdev *) * - ARRAY_SIZE(vpfe->cfg->asd), GFP_KERNEL); + vpfe->sd = devm_kcalloc(&pdev->dev, + ARRAY_SIZE(vpfe->cfg->asd), + sizeof(struct v4l2_subdev *), + GFP_KERNEL); if (!vpfe->sd) { ret = -ENOMEM; goto probe_out_v4l2_unregister; diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index 9364cdf62f54..a96f53ce8088 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -1528,8 +1528,10 @@ vpif_capture_get_pdata(struct platform_device *pdev) if (!pdata) return NULL; pdata->subdev_info = - devm_kzalloc(&pdev->dev, sizeof(*pdata->subdev_info) * - VPIF_CAPTURE_NUM_CHANNELS, GFP_KERNEL); + devm_kcalloc(&pdev->dev, + VPIF_CAPTURE_NUM_CHANNELS, + sizeof(*pdata->subdev_info), + GFP_KERNEL); if (!pdata->subdev_info) return NULL; @@ -1546,9 +1548,9 @@ vpif_capture_get_pdata(struct platform_device *pdev) sdinfo = &pdata->subdev_info[i]; chan = &pdata->chan_config[i]; - chan->inputs = devm_kzalloc(&pdev->dev, - sizeof(*chan->inputs) * + chan->inputs = devm_kcalloc(&pdev->dev, VPIF_CAPTURE_NUM_CHANNELS, + sizeof(*chan->inputs), GFP_KERNEL); if (!chan->inputs) return NULL; diff --git a/drivers/media/platform/marvell-ccic/mmp-driver.c b/drivers/media/platform/marvell-ccic/mmp-driver.c index 3cf300072348..6d9f0abb2660 100644 --- a/drivers/media/platform/marvell-ccic/mmp-driver.c +++ b/drivers/media/platform/marvell-ccic/mmp-driver.c @@ -12,7 +12,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/i2c.h> -#include <linux/i2c-gpio.h> +#include <linux/platform_data/i2c-gpio.h> #include <linux/interrupt.h> #include <linux/spinlock.h> #include <linux/slab.h> diff --git a/drivers/media/platform/qcom/camss-8x16/camss-csid.c b/drivers/media/platform/qcom/camss-8x16/camss-csid.c index 64df82817de3..226f36ef7419 100644 --- a/drivers/media/platform/qcom/camss-8x16/camss-csid.c +++ b/drivers/media/platform/qcom/camss-8x16/camss-csid.c @@ -845,7 +845,7 @@ int msm_csid_subdev_init(struct csid_device *csid, while (res->clock[csid->nclocks]) csid->nclocks++; - csid->clock = devm_kzalloc(dev, csid->nclocks * sizeof(*csid->clock), + csid->clock = devm_kcalloc(dev, csid->nclocks, sizeof(*csid->clock), GFP_KERNEL); if (!csid->clock) return -ENOMEM; @@ -868,8 +868,10 @@ int msm_csid_subdev_init(struct csid_device *csid, continue; } - clock->freq = devm_kzalloc(dev, clock->nfreqs * - sizeof(*clock->freq), GFP_KERNEL); + clock->freq = devm_kcalloc(dev, + clock->nfreqs, + sizeof(*clock->freq), + GFP_KERNEL); if (!clock->freq) return -ENOMEM; diff --git a/drivers/media/platform/qcom/camss-8x16/camss-csiphy.c b/drivers/media/platform/qcom/camss-8x16/camss-csiphy.c index 072c6cf053f6..7e61caba6a2d 100644 --- a/drivers/media/platform/qcom/camss-8x16/camss-csiphy.c +++ b/drivers/media/platform/qcom/camss-8x16/camss-csiphy.c @@ -732,8 +732,9 @@ int msm_csiphy_subdev_init(struct csiphy_device *csiphy, while (res->clock[csiphy->nclocks]) csiphy->nclocks++; - csiphy->clock = devm_kzalloc(dev, csiphy->nclocks * - sizeof(*csiphy->clock), GFP_KERNEL); + csiphy->clock = devm_kcalloc(dev, + csiphy->nclocks, sizeof(*csiphy->clock), + GFP_KERNEL); if (!csiphy->clock) return -ENOMEM; @@ -755,8 +756,10 @@ int msm_csiphy_subdev_init(struct csiphy_device *csiphy, continue; } - clock->freq = devm_kzalloc(dev, clock->nfreqs * - sizeof(*clock->freq), GFP_KERNEL); + clock->freq = devm_kcalloc(dev, + clock->nfreqs, + sizeof(*clock->freq), + GFP_KERNEL); if (!clock->freq) return -ENOMEM; diff --git a/drivers/media/platform/qcom/camss-8x16/camss-ispif.c b/drivers/media/platform/qcom/camss-8x16/camss-ispif.c index 24da529397b5..9d1af9353c1d 100644 --- a/drivers/media/platform/qcom/camss-8x16/camss-ispif.c +++ b/drivers/media/platform/qcom/camss-8x16/camss-ispif.c @@ -948,7 +948,8 @@ int msm_ispif_subdev_init(struct ispif_device *ispif, while (res->clock[ispif->nclocks]) ispif->nclocks++; - ispif->clock = devm_kzalloc(dev, ispif->nclocks * sizeof(*ispif->clock), + ispif->clock = devm_kcalloc(dev, + ispif->nclocks, sizeof(*ispif->clock), GFP_KERNEL); if (!ispif->clock) return -ENOMEM; @@ -968,8 +969,10 @@ int msm_ispif_subdev_init(struct ispif_device *ispif, while (res->clock_for_reset[ispif->nclocks_for_reset]) ispif->nclocks_for_reset++; - ispif->clock_for_reset = devm_kzalloc(dev, ispif->nclocks_for_reset * - sizeof(*ispif->clock_for_reset), GFP_KERNEL); + ispif->clock_for_reset = devm_kcalloc(dev, + ispif->nclocks_for_reset, + sizeof(*ispif->clock_for_reset), + GFP_KERNEL); if (!ispif->clock_for_reset) return -ENOMEM; diff --git a/drivers/media/platform/qcom/camss-8x16/camss-vfe.c b/drivers/media/platform/qcom/camss-8x16/camss-vfe.c index 55232a912950..a6329a8a7c4a 100644 --- a/drivers/media/platform/qcom/camss-8x16/camss-vfe.c +++ b/drivers/media/platform/qcom/camss-8x16/camss-vfe.c @@ -2794,7 +2794,7 @@ int msm_vfe_subdev_init(struct vfe_device *vfe, const struct resources *res) while (res->clock[vfe->nclocks]) vfe->nclocks++; - vfe->clock = devm_kzalloc(dev, vfe->nclocks * sizeof(*vfe->clock), + vfe->clock = devm_kcalloc(dev, vfe->nclocks, sizeof(*vfe->clock), GFP_KERNEL); if (!vfe->clock) return -ENOMEM; @@ -2817,8 +2817,10 @@ int msm_vfe_subdev_init(struct vfe_device *vfe, const struct resources *res) continue; } - clock->freq = devm_kzalloc(dev, clock->nfreqs * - sizeof(*clock->freq), GFP_KERNEL); + clock->freq = devm_kcalloc(dev, + clock->nfreqs, + sizeof(*clock->freq), + GFP_KERNEL); if (!clock->freq) return -ENOMEM; diff --git a/drivers/media/platform/qcom/camss-8x16/camss.c b/drivers/media/platform/qcom/camss-8x16/camss.c index 05f06c98aa64..23fda6207a23 100644 --- a/drivers/media/platform/qcom/camss-8x16/camss.c +++ b/drivers/media/platform/qcom/camss-8x16/camss.c @@ -271,7 +271,8 @@ static int camss_of_parse_endpoint_node(struct device *dev, lncfg->clk.pol = mipi_csi2->lane_polarities[0]; lncfg->num_data = mipi_csi2->num_data_lanes; - lncfg->data = devm_kzalloc(dev, lncfg->num_data * sizeof(*lncfg->data), + lncfg->data = devm_kcalloc(dev, + lncfg->num_data, sizeof(*lncfg->data), GFP_KERNEL); if (!lncfg->data) return -ENOMEM; diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index 69f0d8e80bd8..66d613629167 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -481,7 +481,8 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd) return -ENXIO; icd->user_formats = - vmalloc(fmts * sizeof(struct soc_camera_format_xlate)); + vmalloc(array_size(fmts, + sizeof(struct soc_camera_format_xlate))); if (!icd->user_formats) return -ENOMEM; diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c index 82ec216f2ad8..31db363602e5 100644 --- a/drivers/media/platform/vivid/vivid-core.c +++ b/drivers/media/platform/vivid/vivid-core.c @@ -844,10 +844,10 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) tpg_init(&dev->tpg, 640, 360); if (tpg_alloc(&dev->tpg, MAX_ZOOM * MAX_WIDTH)) goto free_dev; - dev->scaled_line = vzalloc(MAX_ZOOM * MAX_WIDTH); + dev->scaled_line = vzalloc(array_size(MAX_WIDTH, MAX_ZOOM)); if (!dev->scaled_line) goto free_dev; - dev->blended_line = vzalloc(MAX_ZOOM * MAX_WIDTH); + dev->blended_line = vzalloc(array_size(MAX_WIDTH, MAX_ZOOM)); if (!dev->blended_line) goto free_dev; @@ -859,8 +859,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) /* create a string array containing the names of all the preset timings */ while (v4l2_dv_timings_presets[dev->query_dv_timings_size].bt.width) dev->query_dv_timings_size++; - dev->query_dv_timings_qmenu = kmalloc(dev->query_dv_timings_size * - (sizeof(void *) + 32), GFP_KERNEL); + dev->query_dv_timings_qmenu = kmalloc_array(dev->query_dv_timings_size, + (sizeof(void *) + 32), + GFP_KERNEL); if (dev->query_dv_timings_qmenu == NULL) goto free_dev; for (i = 0; i < dev->query_dv_timings_size; i++) { diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c index da276a85aa95..36a29e13109e 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.c +++ b/drivers/media/platform/vsp1/vsp1_entity.c @@ -630,7 +630,8 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, entity->source_pad = num_pads - 1; /* Allocate and initialize pads. */ - entity->pads = devm_kzalloc(vsp1->dev, num_pads * sizeof(*entity->pads), + entity->pads = devm_kcalloc(vsp1->dev, + num_pads, sizeof(*entity->pads), GFP_KERNEL); if (entity->pads == NULL) return -ENOMEM; diff --git a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c index 6bb28cd49dae..6d95ec1e9a6b 100644 --- a/drivers/media/platform/xilinx/xilinx-vipp.c +++ b/drivers/media/platform/xilinx/xilinx-vipp.c @@ -532,7 +532,7 @@ static int xvip_graph_init(struct xvip_composite_device *xdev) /* Register the subdevices notifier. */ num_subdevs = xdev->num_subdevs; - subdevs = devm_kzalloc(xdev->dev, sizeof(*subdevs) * num_subdevs, + subdevs = devm_kcalloc(xdev->dev, num_subdevs, sizeof(*subdevs), GFP_KERNEL); if (subdevs == NULL) { ret = -ENOMEM; diff --git a/drivers/media/rc/ir-rx51.c b/drivers/media/rc/ir-rx51.c index 49265f02e772..8a93f7468622 100644 --- a/drivers/media/rc/ir-rx51.c +++ b/drivers/media/rc/ir-rx51.c @@ -22,7 +22,6 @@ #include <linux/hrtimer.h> #include <media/rc-core.h> -#include <linux/platform_data/media/ir-rx51.h> #define WBUF_LEN 256 @@ -31,7 +30,6 @@ struct ir_rx51 { struct pwm_device *pwm; struct hrtimer timer; struct device *dev; - struct ir_rx51_platform_data *pdata; wait_queue_head_t wqueue; unsigned int freq; /* carrier frequency */ @@ -130,10 +128,9 @@ static int ir_rx51_tx(struct rc_dev *dev, unsigned int *buffer, ir_rx51->wbuf[count] = -1; /* Insert termination mark */ /* - * Adjust latency requirements so the device doesn't go in too - * deep sleep states + * REVISIT: Adjust latency requirements so the device doesn't go in too + * deep sleep states with pm_qos_add_request(). */ - ir_rx51->pdata->set_max_mpu_wakeup_lat(ir_rx51->dev, 50); ir_rx51_on(ir_rx51); ir_rx51->wbuf_index = 1; @@ -146,8 +143,7 @@ static int ir_rx51_tx(struct rc_dev *dev, unsigned int *buffer, */ wait_event_interruptible(ir_rx51->wqueue, ir_rx51->wbuf_index < 0); - /* We can sleep again */ - ir_rx51->pdata->set_max_mpu_wakeup_lat(ir_rx51->dev, -1); + /* REVISIT: Remove pm_qos constraint, we can sleep again */ return count; } @@ -244,13 +240,6 @@ static int ir_rx51_probe(struct platform_device *dev) struct pwm_device *pwm; struct rc_dev *rcdev; - ir_rx51.pdata = dev->dev.platform_data; - - if (!ir_rx51.pdata) { - dev_err(&dev->dev, "Platform Data is missing\n"); - return -ENXIO; - } - pwm = pwm_get(&dev->dev, NULL); if (IS_ERR(pwm)) { int err = PTR_ERR(pwm); diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 964cd7bcdd2c..70e187971590 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -217,14 +217,14 @@ static int au0828_init_isoc(struct au0828_dev *dev, int max_packets, dev->isoc_ctl.isoc_copy = isoc_copy; dev->isoc_ctl.num_bufs = num_bufs; - dev->isoc_ctl.urb = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL); + dev->isoc_ctl.urb = kcalloc(num_bufs, sizeof(void *), GFP_KERNEL); if (!dev->isoc_ctl.urb) { au0828_isocdbg("cannot alloc memory for usb buffers\n"); return -ENOMEM; } - dev->isoc_ctl.transfer_buffer = kzalloc(sizeof(void *)*num_bufs, - GFP_KERNEL); + dev->isoc_ctl.transfer_buffer = kcalloc(num_bufs, sizeof(void *), + GFP_KERNEL); if (!dev->isoc_ctl.transfer_buffer) { au0828_isocdbg("cannot allocate memory for usb transfer\n"); kfree(dev->isoc_ctl.urb); diff --git a/drivers/media/usb/cpia2/cpia2_usb.c b/drivers/media/usb/cpia2/cpia2_usb.c index b51fc372ca25..a771e0a52610 100644 --- a/drivers/media/usb/cpia2/cpia2_usb.c +++ b/drivers/media/usb/cpia2/cpia2_usb.c @@ -663,7 +663,8 @@ static int submit_urbs(struct camera_data *cam) if (cam->sbuf[i].data) continue; cam->sbuf[i].data = - kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL); + kmalloc_array(FRAME_SIZE_PER_DESC, FRAMES_PER_DESC, + GFP_KERNEL); if (!cam->sbuf[i].data) { while (--i >= 0) { kfree(cam->sbuf[i].data); diff --git a/drivers/media/usb/cx231xx/cx231xx-audio.c b/drivers/media/usb/cx231xx/cx231xx-audio.c index d96236d786d1..c4a84fb930b6 100644 --- a/drivers/media/usb/cx231xx/cx231xx-audio.c +++ b/drivers/media/usb/cx231xx/cx231xx-audio.c @@ -710,7 +710,7 @@ static int cx231xx_audio_init(struct cx231xx *dev) dev_info(dev->dev, "audio EndPoint Addr 0x%x, Alternate settings: %i\n", adev->end_point_addr, adev->num_alt); - adev->alt_max_pkt_size = kmalloc(32 * adev->num_alt, GFP_KERNEL); + adev->alt_max_pkt_size = kmalloc_array(32, adev->num_alt, GFP_KERNEL); if (!adev->alt_max_pkt_size) { err = -ENOMEM; goto err_free_card; diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c b/drivers/media/usb/cx231xx/cx231xx-core.c index 4f43668df15d..53d846dea3d2 100644 --- a/drivers/media/usb/cx231xx/cx231xx-core.c +++ b/drivers/media/usb/cx231xx/cx231xx-core.c @@ -1034,7 +1034,7 @@ int cx231xx_init_isoc(struct cx231xx *dev, int max_packets, dma_q->partial_buf[i] = 0; dev->video_mode.isoc_ctl.urb = - kzalloc(sizeof(void *) * num_bufs, GFP_KERNEL); + kcalloc(num_bufs, sizeof(void *), GFP_KERNEL); if (!dev->video_mode.isoc_ctl.urb) { dev_err(dev->dev, "cannot alloc memory for usb buffers\n"); @@ -1042,7 +1042,7 @@ int cx231xx_init_isoc(struct cx231xx *dev, int max_packets, } dev->video_mode.isoc_ctl.transfer_buffer = - kzalloc(sizeof(void *) * num_bufs, GFP_KERNEL); + kcalloc(num_bufs, sizeof(void *), GFP_KERNEL); if (!dev->video_mode.isoc_ctl.transfer_buffer) { dev_err(dev->dev, "cannot allocate memory for usbtransfer\n"); @@ -1169,7 +1169,7 @@ int cx231xx_init_bulk(struct cx231xx *dev, int max_packets, dma_q->partial_buf[i] = 0; dev->video_mode.bulk_ctl.urb = - kzalloc(sizeof(void *) * num_bufs, GFP_KERNEL); + kcalloc(num_bufs, sizeof(void *), GFP_KERNEL); if (!dev->video_mode.bulk_ctl.urb) { dev_err(dev->dev, "cannot alloc memory for usb buffers\n"); @@ -1177,7 +1177,7 @@ int cx231xx_init_bulk(struct cx231xx *dev, int max_packets, } dev->video_mode.bulk_ctl.transfer_buffer = - kzalloc(sizeof(void *) * num_bufs, GFP_KERNEL); + kcalloc(num_bufs, sizeof(void *), GFP_KERNEL); if (!dev->video_mode.bulk_ctl.transfer_buffer) { dev_err(dev->dev, "cannot allocate memory for usbtransfer\n"); diff --git a/drivers/media/usb/cx231xx/cx231xx-vbi.c b/drivers/media/usb/cx231xx/cx231xx-vbi.c index d3bfe8e23b1f..b621cf1aa96b 100644 --- a/drivers/media/usb/cx231xx/cx231xx-vbi.c +++ b/drivers/media/usb/cx231xx/cx231xx-vbi.c @@ -415,7 +415,7 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets, for (i = 0; i < 8; i++) dma_q->partial_buf[i] = 0; - dev->vbi_mode.bulk_ctl.urb = kzalloc(sizeof(void *) * num_bufs, + dev->vbi_mode.bulk_ctl.urb = kcalloc(num_bufs, sizeof(void *), GFP_KERNEL); if (!dev->vbi_mode.bulk_ctl.urb) { dev_err(dev->dev, @@ -424,7 +424,7 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets, } dev->vbi_mode.bulk_ctl.transfer_buffer = - kzalloc(sizeof(void *) * num_bufs, GFP_KERNEL); + kcalloc(num_bufs, sizeof(void *), GFP_KERNEL); if (!dev->vbi_mode.bulk_ctl.transfer_buffer) { dev_err(dev->dev, "cannot allocate memory for usbtransfer\n"); diff --git a/drivers/media/usb/go7007/go7007-fw.c b/drivers/media/usb/go7007/go7007-fw.c index 87b4fc48ef09..24f5b615dc7a 100644 --- a/drivers/media/usb/go7007/go7007-fw.c +++ b/drivers/media/usb/go7007/go7007-fw.c @@ -1579,7 +1579,7 @@ int go7007_construct_fw_image(struct go7007 *go, u8 **fw, int *fwlen) GO7007_FW_NAME); return -1; } - code = kzalloc(codespace * 2, GFP_KERNEL); + code = kcalloc(codespace, 2, GFP_KERNEL); if (code == NULL) goto fw_failed; diff --git a/drivers/media/usb/go7007/go7007-usb.c b/drivers/media/usb/go7007/go7007-usb.c index ed9bcaf08d5e..19c6a0354ce0 100644 --- a/drivers/media/usb/go7007/go7007-usb.c +++ b/drivers/media/usb/go7007/go7007-usb.c @@ -1143,7 +1143,8 @@ static int go7007_usb_probe(struct usb_interface *intf, usb->intr_urb = usb_alloc_urb(0, GFP_KERNEL); if (usb->intr_urb == NULL) goto allocfail; - usb->intr_urb->transfer_buffer = kmalloc(2*sizeof(u16), GFP_KERNEL); + usb->intr_urb->transfer_buffer = kmalloc_array(2, sizeof(u16), + GFP_KERNEL); if (usb->intr_urb->transfer_buffer == NULL) goto allocfail; diff --git a/drivers/media/usb/gspca/t613.c b/drivers/media/usb/gspca/t613.c index 0ae557cd15ef..445782919446 100644 --- a/drivers/media/usb/gspca/t613.c +++ b/drivers/media/usb/gspca/t613.c @@ -363,7 +363,7 @@ static void reg_w_ixbuf(struct gspca_dev *gspca_dev, if (len * 2 <= USB_BUF_SZ) { p = tmpbuf = gspca_dev->usb_buf; } else { - p = tmpbuf = kmalloc(len * 2, GFP_KERNEL); + p = tmpbuf = kmalloc_array(len, 2, GFP_KERNEL); if (!tmpbuf) { pr_err("Out of memory\n"); return; diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c index e0353161ccd6..a8519da0020b 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c @@ -2413,7 +2413,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, hdw->control_cnt = CTRLDEF_COUNT; hdw->control_cnt += MPEGDEF_COUNT; - hdw->controls = kzalloc(sizeof(struct pvr2_ctrl) * hdw->control_cnt, + hdw->controls = kcalloc(hdw->control_cnt, sizeof(struct pvr2_ctrl), GFP_KERNEL); if (!hdw->controls) goto fail; hdw->hdw_desc = hdw_desc; diff --git a/drivers/media/usb/pvrusb2/pvrusb2-std.c b/drivers/media/usb/pvrusb2/pvrusb2-std.c index 21bb20dba82c..6b651f8b54df 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-std.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-std.c @@ -361,7 +361,7 @@ struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr, std_cnt); if (!std_cnt) return NULL; // paranoia - stddefs = kzalloc(sizeof(struct v4l2_standard) * std_cnt, + stddefs = kcalloc(std_cnt, sizeof(struct v4l2_standard), GFP_KERNEL); if (!stddefs) return NULL; diff --git a/drivers/media/usb/stk1160/stk1160-core.c b/drivers/media/usb/stk1160/stk1160-core.c index 72bd893c9659..468f5ccf4ae6 100644 --- a/drivers/media/usb/stk1160/stk1160-core.c +++ b/drivers/media/usb/stk1160/stk1160-core.c @@ -290,8 +290,9 @@ static int stk1160_probe(struct usb_interface *interface, return -ENODEV; /* Alloc an array for all possible max_pkt_size */ - alt_max_pkt_size = kmalloc(sizeof(alt_max_pkt_size[0]) * - interface->num_altsetting, GFP_KERNEL); + alt_max_pkt_size = kmalloc_array(interface->num_altsetting, + sizeof(alt_max_pkt_size[0]), + GFP_KERNEL); if (alt_max_pkt_size == NULL) return -ENOMEM; diff --git a/drivers/media/usb/stk1160/stk1160-video.c b/drivers/media/usb/stk1160/stk1160-video.c index 423c03a0638d..2811f612820f 100644 --- a/drivers/media/usb/stk1160/stk1160-video.c +++ b/drivers/media/usb/stk1160/stk1160-video.c @@ -439,14 +439,14 @@ int stk1160_alloc_isoc(struct stk1160 *dev) dev->isoc_ctl.buf = NULL; dev->isoc_ctl.max_pkt_size = dev->max_pkt_size; - dev->isoc_ctl.urb = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL); + dev->isoc_ctl.urb = kcalloc(num_bufs, sizeof(void *), GFP_KERNEL); if (!dev->isoc_ctl.urb) { stk1160_err("out of memory for urb array\n"); return -ENOMEM; } - dev->isoc_ctl.transfer_buffer = kzalloc(sizeof(void *)*num_bufs, - GFP_KERNEL); + dev->isoc_ctl.transfer_buffer = kcalloc(num_bufs, sizeof(void *), + GFP_KERNEL); if (!dev->isoc_ctl.transfer_buffer) { stk1160_err("out of memory for usb transfers\n"); kfree(dev->isoc_ctl.urb); diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index 22389b56ec24..5accb5241072 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.c +++ b/drivers/media/usb/stkwebcam/stk-webcam.c @@ -567,8 +567,9 @@ static int stk_prepare_sio_buffers(struct stk_camera *dev, unsigned n_sbufs) if (dev->sio_bufs != NULL) pr_err("sio_bufs already allocated\n"); else { - dev->sio_bufs = kzalloc(n_sbufs * sizeof(struct stk_sio_buffer), - GFP_KERNEL); + dev->sio_bufs = kcalloc(n_sbufs, + sizeof(struct stk_sio_buffer), + GFP_KERNEL); if (dev->sio_bufs == NULL) return -ENOMEM; for (i = 0; i < n_sbufs; i++) { diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c index aa85fe31c835..96055de6e8ce 100644 --- a/drivers/media/usb/tm6000/tm6000-video.c +++ b/drivers/media/usb/tm6000/tm6000-video.c @@ -463,11 +463,12 @@ static int tm6000_alloc_urb_buffers(struct tm6000_core *dev) if (dev->urb_buffer) return 0; - dev->urb_buffer = kmalloc(sizeof(void *)*num_bufs, GFP_KERNEL); + dev->urb_buffer = kmalloc_array(num_bufs, sizeof(void *), GFP_KERNEL); if (!dev->urb_buffer) return -ENOMEM; - dev->urb_dma = kmalloc(sizeof(dma_addr_t *)*num_bufs, GFP_KERNEL); + dev->urb_dma = kmalloc_array(num_bufs, sizeof(dma_addr_t *), + GFP_KERNEL); if (!dev->urb_dma) return -ENOMEM; @@ -583,12 +584,14 @@ static int tm6000_prepare_isoc(struct tm6000_core *dev) dev->isoc_ctl.num_bufs = num_bufs; - dev->isoc_ctl.urb = kmalloc(sizeof(void *)*num_bufs, GFP_KERNEL); + dev->isoc_ctl.urb = kmalloc_array(num_bufs, sizeof(void *), + GFP_KERNEL); if (!dev->isoc_ctl.urb) return -ENOMEM; - dev->isoc_ctl.transfer_buffer = kmalloc(sizeof(void *)*num_bufs, - GFP_KERNEL); + dev->isoc_ctl.transfer_buffer = kmalloc_array(num_bufs, + sizeof(void *), + GFP_KERNEL); if (!dev->isoc_ctl.transfer_buffer) { kfree(dev->isoc_ctl.urb); return -ENOMEM; diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c index ce79df643c7e..36a9a4017185 100644 --- a/drivers/media/usb/usbtv/usbtv-video.c +++ b/drivers/media/usb/usbtv/usbtv-video.c @@ -507,7 +507,7 @@ static struct urb *usbtv_setup_iso_transfer(struct usbtv *usbtv) ip->pipe = usb_rcvisocpipe(usbtv->udev, USBTV_VIDEO_ENDP); ip->interval = 1; ip->transfer_flags = URB_ISO_ASAP; - ip->transfer_buffer = kzalloc(size * USBTV_ISOC_PACKETS, + ip->transfer_buffer = kcalloc(USBTV_ISOC_PACKETS, size, GFP_KERNEL); if (!ip->transfer_buffer) { usb_free_urb(ip); diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c index 0f5954a1fea2..f29d1bef0293 100644 --- a/drivers/media/usb/usbvision/usbvision-video.c +++ b/drivers/media/usb/usbvision/usbvision-video.c @@ -1492,7 +1492,8 @@ static int usbvision_probe(struct usb_interface *intf, usbvision->num_alt = uif->num_altsetting; PDEBUG(DBG_PROBE, "Alternate settings: %i", usbvision->num_alt); - usbvision->alt_max_pkt_size = kmalloc(32 * usbvision->num_alt, GFP_KERNEL); + usbvision->alt_max_pkt_size = kmalloc_array(32, usbvision->num_alt, + GFP_KERNEL); if (!usbvision->alt_max_pkt_size) { ret = -ENOMEM; goto err_pkt; diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index b28c997a7ab0..a88b2e51a666 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -513,8 +513,8 @@ static int uvc_video_clock_init(struct uvc_streaming *stream) spin_lock_init(&clock->lock); clock->size = 32; - clock->samples = kmalloc(clock->size * sizeof(*clock->samples), - GFP_KERNEL); + clock->samples = kmalloc_array(clock->size, sizeof(*clock->samples), + GFP_KERNEL); if (clock->samples == NULL) return -ENOMEM; diff --git a/drivers/media/v4l2-core/v4l2-event.c b/drivers/media/v4l2-core/v4l2-event.c index 968c2eb08b5a..127fe6eb91d9 100644 --- a/drivers/media/v4l2-core/v4l2-event.c +++ b/drivers/media/v4l2-core/v4l2-event.c @@ -215,8 +215,7 @@ int v4l2_event_subscribe(struct v4l2_fh *fh, if (elems < 1) elems = 1; - sev = kvzalloc(sizeof(*sev) + sizeof(struct v4l2_kevent) * elems, - GFP_KERNEL); + sev = kvzalloc(struct_size(sev, events, elems), GFP_KERNEL); if (!sev) return -ENOMEM; for (i = 0; i < elems; i++) diff --git a/drivers/media/v4l2-core/v4l2-flash-led-class.c b/drivers/media/v4l2-core/v4l2-flash-led-class.c index 4ceef217de83..215b4804ada2 100644 --- a/drivers/media/v4l2-core/v4l2-flash-led-class.c +++ b/drivers/media/v4l2-core/v4l2-flash-led-class.c @@ -412,9 +412,10 @@ static int v4l2_flash_init_controls(struct v4l2_flash *v4l2_flash, struct v4l2_ctrl_config *ctrl_cfg; int i, ret, num_ctrls = 0; - v4l2_flash->ctrls = devm_kzalloc(v4l2_flash->sd.dev, - sizeof(*v4l2_flash->ctrls) * - (STROBE_SOURCE + 1), GFP_KERNEL); + v4l2_flash->ctrls = devm_kcalloc(v4l2_flash->sd.dev, + STROBE_SOURCE + 1, + sizeof(*v4l2_flash->ctrls), + GFP_KERNEL); if (!v4l2_flash->ctrls) return -ENOMEM; diff --git a/drivers/media/v4l2-core/videobuf-dma-sg.c b/drivers/media/v4l2-core/videobuf-dma-sg.c index 2e5c346f9c30..08929c087e27 100644 --- a/drivers/media/v4l2-core/videobuf-dma-sg.c +++ b/drivers/media/v4l2-core/videobuf-dma-sg.c @@ -69,7 +69,7 @@ static struct scatterlist *videobuf_vmalloc_to_sg(unsigned char *virt, struct page *pg; int i; - sglist = vzalloc(nr_pages * sizeof(*sglist)); + sglist = vzalloc(array_size(nr_pages, sizeof(*sglist))); if (NULL == sglist) return NULL; sg_init_table(sglist, nr_pages); @@ -100,7 +100,7 @@ static struct scatterlist *videobuf_pages_to_sg(struct page **pages, if (NULL == pages[0]) return NULL; - sglist = vmalloc(nr_pages * sizeof(*sglist)); + sglist = vmalloc(array_size(nr_pages, sizeof(*sglist))); if (NULL == sglist) return NULL; sg_init_table(sglist, nr_pages); @@ -175,7 +175,8 @@ static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma, dma->offset = data & ~PAGE_MASK; dma->size = size; dma->nr_pages = last-first+1; - dma->pages = kmalloc(dma->nr_pages * sizeof(struct page *), GFP_KERNEL); + dma->pages = kmalloc_array(dma->nr_pages, sizeof(struct page *), + GFP_KERNEL); if (NULL == dma->pages) return -ENOMEM; diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig index 19a0e83f260d..8d731d6c3e54 100644 --- a/drivers/memory/Kconfig +++ b/drivers/memory/Kconfig @@ -104,16 +104,6 @@ config MVEBU_DEVBUS Armada 370 and Armada XP. This controller allows to handle flash devices such as NOR, NAND, SRAM, and FPGA. -config TEGRA20_MC - bool "Tegra20 Memory Controller(MC) driver" - default y - depends on ARCH_TEGRA_2x_SOC - help - This driver is for the Memory Controller(MC) module available - in Tegra20 SoCs, mainly for a address translation fault - analysis, especially for IOMMU/GART(Graphics Address - Relocation Table) module. - config FSL_CORENET_CF tristate "Freescale CoreNet Error Reporting" depends on FSL_SOC_BOOKE diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile index 66f55240830e..a01ab3e22f94 100644 --- a/drivers/memory/Makefile +++ b/drivers/memory/Makefile @@ -16,7 +16,6 @@ obj-$(CONFIG_OMAP_GPMC) += omap-gpmc.o obj-$(CONFIG_FSL_CORENET_CF) += fsl-corenet-cf.o obj-$(CONFIG_FSL_IFC) += fsl_ifc.o obj-$(CONFIG_MVEBU_DEVBUS) += mvebu-devbus.o -obj-$(CONFIG_TEGRA20_MC) += tegra20-mc.o obj-$(CONFIG_JZ4780_NEMC) += jz4780-nemc.o obj-$(CONFIG_MTK_SMI) += mtk-smi.o obj-$(CONFIG_DA8XX_DDRCTL) += da8xx-ddrctl.o diff --git a/drivers/memory/brcmstb_dpfe.c b/drivers/memory/brcmstb_dpfe.c index e9c1485c32b9..04599eccd604 100644 --- a/drivers/memory/brcmstb_dpfe.c +++ b/drivers/memory/brcmstb_dpfe.c @@ -176,7 +176,6 @@ struct private_data { void __iomem *dmem; void __iomem *imem; struct device *dev; - unsigned int index; struct mutex lock; }; @@ -674,10 +673,8 @@ static int brcmstb_dpfe_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct private_data *priv; - struct device *dpfe_dev; struct init_data init; struct resource *res; - u32 index; int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -687,11 +684,6 @@ static int brcmstb_dpfe_probe(struct platform_device *pdev) mutex_init(&priv->lock); platform_set_drvdata(pdev, priv); - /* Cell index is optional; default to 0 if not present. */ - ret = of_property_read_u32(dev->of_node, "cell-index", &index); - if (ret) - index = 0; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dpfe-cpu"); priv->regs = devm_ioremap_resource(dev, res); if (IS_ERR(priv->regs)) { @@ -715,35 +707,20 @@ static int brcmstb_dpfe_probe(struct platform_device *pdev) ret = brcmstb_dpfe_download_firmware(pdev, &init); if (ret) - goto err; - - dpfe_dev = devm_kzalloc(dev, sizeof(*dpfe_dev), GFP_KERNEL); - if (!dpfe_dev) { - ret = -ENOMEM; - goto err; - } - - priv->dev = dpfe_dev; - priv->index = index; + return ret; - dpfe_dev->parent = dev; - dpfe_dev->groups = dpfe_groups; - dpfe_dev->of_node = dev->of_node; - dev_set_drvdata(dpfe_dev, priv); - dev_set_name(dpfe_dev, "dpfe%u", index); + ret = sysfs_create_groups(&pdev->dev.kobj, dpfe_groups); + if (!ret) + dev_info(dev, "registered.\n"); - ret = device_register(dpfe_dev); - if (ret) - goto err; + return ret; +} - dev_info(dev, "registered.\n"); +static int brcmstb_dpfe_remove(struct platform_device *pdev) +{ + sysfs_remove_groups(&pdev->dev.kobj, dpfe_groups); return 0; - -err: - dev_err(dev, "failed to initialize -- error %d\n", ret); - - return ret; } static const struct of_device_id brcmstb_dpfe_of_match[] = { @@ -758,6 +735,7 @@ static struct platform_driver brcmstb_dpfe_driver = { .of_match_table = brcmstb_dpfe_of_match, }, .probe = brcmstb_dpfe_probe, + .remove = brcmstb_dpfe_remove, .resume = brcmstb_dpfe_resume, }; diff --git a/drivers/memory/of_memory.c b/drivers/memory/of_memory.c index 568f05ed961a..2f5ed7366eec 100644 --- a/drivers/memory/of_memory.c +++ b/drivers/memory/of_memory.c @@ -126,8 +126,8 @@ const struct lpddr2_timings *of_get_ddr_timings(struct device_node *np_ddr, arr_sz++; if (arr_sz) - timings = devm_kzalloc(dev, sizeof(*timings) * arr_sz, - GFP_KERNEL); + timings = devm_kcalloc(dev, arr_sz, sizeof(*timings), + GFP_KERNEL); if (!timings) goto default_timings; diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c index 90a66b3f7ae1..c215287e80cf 100644 --- a/drivers/memory/omap-gpmc.c +++ b/drivers/memory/omap-gpmc.c @@ -2060,8 +2060,8 @@ static int gpmc_probe_generic_child(struct platform_device *pdev, * timings. */ name = gpmc_cs_get_name(cs); - if (name && child->name && of_node_cmp(child->name, name) == 0) - goto no_timings; + if (name && of_node_cmp(child->name, name) == 0) + goto no_timings; ret = gpmc_cs_request(cs, resource_size(&res), &base); if (ret < 0) { diff --git a/drivers/memory/tegra/Makefile b/drivers/memory/tegra/Makefile index ce87a9470034..94ab16ba075b 100644 --- a/drivers/memory/tegra/Makefile +++ b/drivers/memory/tegra/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 tegra-mc-y := mc.o +tegra-mc-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20.o tegra-mc-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30.o tegra-mc-$(CONFIG_ARCH_TEGRA_114_SOC) += tegra114.o tegra-mc-$(CONFIG_ARCH_TEGRA_124_SOC) += tegra124.o diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c index a4803ac192bb..bb93cc53554e 100644 --- a/drivers/memory/tegra/mc.c +++ b/drivers/memory/tegra/mc.c @@ -7,6 +7,7 @@ */ #include <linux/clk.h> +#include <linux/delay.h> #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/module.h> @@ -20,14 +21,6 @@ #include "mc.h" #define MC_INTSTATUS 0x000 -#define MC_INT_DECERR_MTS (1 << 16) -#define MC_INT_SECERR_SEC (1 << 13) -#define MC_INT_DECERR_VPR (1 << 12) -#define MC_INT_INVALID_APB_ASID_UPDATE (1 << 11) -#define MC_INT_INVALID_SMMU_PAGE (1 << 10) -#define MC_INT_ARBITRATION_EMEM (1 << 9) -#define MC_INT_SECURITY_VIOLATION (1 << 8) -#define MC_INT_DECERR_EMEM (1 << 6) #define MC_INTMASK 0x004 @@ -45,6 +38,9 @@ #define MC_ERR_ADR 0x0c +#define MC_DECERR_EMEM_OTHERS_STATUS 0x58 +#define MC_SECURITY_VIOLATION_STATUS 0x74 + #define MC_EMEM_ARB_CFG 0x90 #define MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE(x) (((x) & 0x1ff) << 0) #define MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE_MASK 0x1ff @@ -54,6 +50,9 @@ #define MC_EMEM_ADR_CFG_EMEM_NUMDEV BIT(0) static const struct of_device_id tegra_mc_of_match[] = { +#ifdef CONFIG_ARCH_TEGRA_2x_SOC + { .compatible = "nvidia,tegra20-mc", .data = &tegra20_mc_soc }, +#endif #ifdef CONFIG_ARCH_TEGRA_3x_SOC { .compatible = "nvidia,tegra30-mc", .data = &tegra30_mc_soc }, #endif @@ -73,6 +72,207 @@ static const struct of_device_id tegra_mc_of_match[] = { }; MODULE_DEVICE_TABLE(of, tegra_mc_of_match); +static int terga_mc_block_dma_common(struct tegra_mc *mc, + const struct tegra_mc_reset *rst) +{ + unsigned long flags; + u32 value; + + spin_lock_irqsave(&mc->lock, flags); + + value = mc_readl(mc, rst->control) | BIT(rst->bit); + mc_writel(mc, value, rst->control); + + spin_unlock_irqrestore(&mc->lock, flags); + + return 0; +} + +static bool terga_mc_dma_idling_common(struct tegra_mc *mc, + const struct tegra_mc_reset *rst) +{ + return (mc_readl(mc, rst->status) & BIT(rst->bit)) != 0; +} + +static int terga_mc_unblock_dma_common(struct tegra_mc *mc, + const struct tegra_mc_reset *rst) +{ + unsigned long flags; + u32 value; + + spin_lock_irqsave(&mc->lock, flags); + + value = mc_readl(mc, rst->control) & ~BIT(rst->bit); + mc_writel(mc, value, rst->control); + + spin_unlock_irqrestore(&mc->lock, flags); + + return 0; +} + +static int terga_mc_reset_status_common(struct tegra_mc *mc, + const struct tegra_mc_reset *rst) +{ + return (mc_readl(mc, rst->control) & BIT(rst->bit)) != 0; +} + +const struct tegra_mc_reset_ops terga_mc_reset_ops_common = { + .block_dma = terga_mc_block_dma_common, + .dma_idling = terga_mc_dma_idling_common, + .unblock_dma = terga_mc_unblock_dma_common, + .reset_status = terga_mc_reset_status_common, +}; + +static inline struct tegra_mc *reset_to_mc(struct reset_controller_dev *rcdev) +{ + return container_of(rcdev, struct tegra_mc, reset); +} + +static const struct tegra_mc_reset *tegra_mc_reset_find(struct tegra_mc *mc, + unsigned long id) +{ + unsigned int i; + + for (i = 0; i < mc->soc->num_resets; i++) + if (mc->soc->resets[i].id == id) + return &mc->soc->resets[i]; + + return NULL; +} + +static int tegra_mc_hotreset_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct tegra_mc *mc = reset_to_mc(rcdev); + const struct tegra_mc_reset_ops *rst_ops; + const struct tegra_mc_reset *rst; + int retries = 500; + int err; + + rst = tegra_mc_reset_find(mc, id); + if (!rst) + return -ENODEV; + + rst_ops = mc->soc->reset_ops; + if (!rst_ops) + return -ENODEV; + + if (rst_ops->block_dma) { + /* block clients DMA requests */ + err = rst_ops->block_dma(mc, rst); + if (err) { + dev_err(mc->dev, "Failed to block %s DMA: %d\n", + rst->name, err); + return err; + } + } + + if (rst_ops->dma_idling) { + /* wait for completion of the outstanding DMA requests */ + while (!rst_ops->dma_idling(mc, rst)) { + if (!retries--) { + dev_err(mc->dev, "Failed to flush %s DMA\n", + rst->name); + return -EBUSY; + } + + usleep_range(10, 100); + } + } + + if (rst_ops->hotreset_assert) { + /* clear clients DMA requests sitting before arbitration */ + err = rst_ops->hotreset_assert(mc, rst); + if (err) { + dev_err(mc->dev, "Failed to hot reset %s: %d\n", + rst->name, err); + return err; + } + } + + return 0; +} + +static int tegra_mc_hotreset_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct tegra_mc *mc = reset_to_mc(rcdev); + const struct tegra_mc_reset_ops *rst_ops; + const struct tegra_mc_reset *rst; + int err; + + rst = tegra_mc_reset_find(mc, id); + if (!rst) + return -ENODEV; + + rst_ops = mc->soc->reset_ops; + if (!rst_ops) + return -ENODEV; + + if (rst_ops->hotreset_deassert) { + /* take out client from hot reset */ + err = rst_ops->hotreset_deassert(mc, rst); + if (err) { + dev_err(mc->dev, "Failed to deassert hot reset %s: %d\n", + rst->name, err); + return err; + } + } + + if (rst_ops->unblock_dma) { + /* allow new DMA requests to proceed to arbitration */ + err = rst_ops->unblock_dma(mc, rst); + if (err) { + dev_err(mc->dev, "Failed to unblock %s DMA : %d\n", + rst->name, err); + return err; + } + } + + return 0; +} + +static int tegra_mc_hotreset_status(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct tegra_mc *mc = reset_to_mc(rcdev); + const struct tegra_mc_reset_ops *rst_ops; + const struct tegra_mc_reset *rst; + + rst = tegra_mc_reset_find(mc, id); + if (!rst) + return -ENODEV; + + rst_ops = mc->soc->reset_ops; + if (!rst_ops) + return -ENODEV; + + return rst_ops->reset_status(mc, rst); +} + +static const struct reset_control_ops tegra_mc_reset_ops = { + .assert = tegra_mc_hotreset_assert, + .deassert = tegra_mc_hotreset_deassert, + .status = tegra_mc_hotreset_status, +}; + +static int tegra_mc_reset_setup(struct tegra_mc *mc) +{ + int err; + + mc->reset.ops = &tegra_mc_reset_ops; + mc->reset.owner = THIS_MODULE; + mc->reset.of_node = mc->dev->of_node; + mc->reset.of_reset_n_cells = 1; + mc->reset.nr_resets = mc->soc->num_resets; + + err = reset_controller_register(&mc->reset); + if (err < 0) + return err; + + return 0; +} + static int tegra_mc_setup_latency_allowance(struct tegra_mc *mc) { unsigned long long tick; @@ -229,6 +429,7 @@ static int tegra_mc_setup_timings(struct tegra_mc *mc) static const char *const status_names[32] = { [ 1] = "External interrupt", [ 6] = "EMEM address decode error", + [ 7] = "GART page fault", [ 8] = "Security violation", [ 9] = "EMEM arbitration error", [10] = "Page fault", @@ -248,12 +449,13 @@ static const char *const error_names[8] = { static irqreturn_t tegra_mc_irq(int irq, void *data) { struct tegra_mc *mc = data; - unsigned long status, mask; + unsigned long status; unsigned int bit; /* mask all interrupts to avoid flooding */ - status = mc_readl(mc, MC_INTSTATUS); - mask = mc_readl(mc, MC_INTMASK); + status = mc_readl(mc, MC_INTSTATUS) & mc->soc->intmask; + if (!status) + return IRQ_NONE; for_each_set_bit(bit, &status, 32) { const char *error = status_names[bit] ?: "unknown"; @@ -341,12 +543,78 @@ static irqreturn_t tegra_mc_irq(int irq, void *data) return IRQ_HANDLED; } +static __maybe_unused irqreturn_t tegra20_mc_irq(int irq, void *data) +{ + struct tegra_mc *mc = data; + unsigned long status; + unsigned int bit; + + /* mask all interrupts to avoid flooding */ + status = mc_readl(mc, MC_INTSTATUS) & mc->soc->intmask; + if (!status) + return IRQ_NONE; + + for_each_set_bit(bit, &status, 32) { + const char *direction = "read", *secure = ""; + const char *error = status_names[bit]; + const char *client, *desc; + phys_addr_t addr; + u32 value, reg; + u8 id, type; + + switch (BIT(bit)) { + case MC_INT_DECERR_EMEM: + reg = MC_DECERR_EMEM_OTHERS_STATUS; + value = mc_readl(mc, reg); + + id = value & mc->soc->client_id_mask; + desc = error_names[2]; + + if (value & BIT(31)) + direction = "write"; + break; + + case MC_INT_INVALID_GART_PAGE: + dev_err_ratelimited(mc->dev, "%s\n", error); + continue; + + case MC_INT_SECURITY_VIOLATION: + reg = MC_SECURITY_VIOLATION_STATUS; + value = mc_readl(mc, reg); + + id = value & mc->soc->client_id_mask; + type = (value & BIT(30)) ? 4 : 3; + desc = error_names[type]; + secure = "secure "; + + if (value & BIT(31)) + direction = "write"; + break; + + default: + continue; + } + + client = mc->soc->clients[id].name; + addr = mc_readl(mc, reg + sizeof(u32)); + + dev_err_ratelimited(mc->dev, "%s: %s%s @%pa: %s (%s)\n", + client, secure, direction, &addr, error, + desc); + } + + /* clear interrupts */ + mc_writel(mc, status, MC_INTSTATUS); + + return IRQ_HANDLED; +} + static int tegra_mc_probe(struct platform_device *pdev) { const struct of_device_id *match; struct resource *res; struct tegra_mc *mc; - u32 value; + void *isr; int err; match = of_match_node(tegra_mc_of_match, pdev->dev.of_node); @@ -358,6 +626,7 @@ static int tegra_mc_probe(struct platform_device *pdev) return -ENOMEM; platform_set_drvdata(pdev, mc); + spin_lock_init(&mc->lock); mc->soc = match->data; mc->dev = &pdev->dev; @@ -369,18 +638,32 @@ static int tegra_mc_probe(struct platform_device *pdev) if (IS_ERR(mc->regs)) return PTR_ERR(mc->regs); - mc->clk = devm_clk_get(&pdev->dev, "mc"); - if (IS_ERR(mc->clk)) { - dev_err(&pdev->dev, "failed to get MC clock: %ld\n", - PTR_ERR(mc->clk)); - return PTR_ERR(mc->clk); - } +#ifdef CONFIG_ARCH_TEGRA_2x_SOC + if (mc->soc == &tegra20_mc_soc) { + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + mc->regs2 = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(mc->regs2)) + return PTR_ERR(mc->regs2); - err = tegra_mc_setup_latency_allowance(mc); - if (err < 0) { - dev_err(&pdev->dev, "failed to setup latency allowance: %d\n", - err); - return err; + isr = tegra20_mc_irq; + } else +#endif + { + mc->clk = devm_clk_get(&pdev->dev, "mc"); + if (IS_ERR(mc->clk)) { + dev_err(&pdev->dev, "failed to get MC clock: %ld\n", + PTR_ERR(mc->clk)); + return PTR_ERR(mc->clk); + } + + err = tegra_mc_setup_latency_allowance(mc); + if (err < 0) { + dev_err(&pdev->dev, "failed to setup latency allowance: %d\n", + err); + return err; + } + + isr = tegra_mc_irq; } err = tegra_mc_setup_timings(mc); @@ -389,13 +672,11 @@ static int tegra_mc_probe(struct platform_device *pdev) return err; } - if (IS_ENABLED(CONFIG_TEGRA_IOMMU_SMMU)) { - mc->smmu = tegra_smmu_probe(&pdev->dev, mc->soc->smmu, mc); - if (IS_ERR(mc->smmu)) { - dev_err(&pdev->dev, "failed to probe SMMU: %ld\n", - PTR_ERR(mc->smmu)); - return PTR_ERR(mc->smmu); - } + err = tegra_mc_reset_setup(mc); + if (err < 0) { + dev_err(&pdev->dev, "failed to register reset controller: %d\n", + err); + return err; } mc->irq = platform_get_irq(pdev, 0); @@ -404,7 +685,11 @@ static int tegra_mc_probe(struct platform_device *pdev) return mc->irq; } - err = devm_request_irq(&pdev->dev, mc->irq, tegra_mc_irq, IRQF_SHARED, + WARN(!mc->soc->client_id_mask, "Missing client ID mask for this SoC\n"); + + mc_writel(mc, mc->soc->intmask, MC_INTMASK); + + err = devm_request_irq(&pdev->dev, mc->irq, isr, IRQF_SHARED, dev_name(&pdev->dev), mc); if (err < 0) { dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n", mc->irq, @@ -412,13 +697,14 @@ static int tegra_mc_probe(struct platform_device *pdev) return err; } - WARN(!mc->soc->client_id_mask, "Missing client ID mask for this SoC\n"); - - value = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR | - MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE | - MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM; - - mc_writel(mc, value, MC_INTMASK); + if (IS_ENABLED(CONFIG_TEGRA_IOMMU_SMMU)) { + mc->smmu = tegra_smmu_probe(&pdev->dev, mc->soc->smmu, mc); + if (IS_ERR(mc->smmu)) { + dev_err(&pdev->dev, "failed to probe SMMU: %ld\n", + PTR_ERR(mc->smmu)); + return PTR_ERR(mc->smmu); + } + } return 0; } diff --git a/drivers/memory/tegra/mc.h b/drivers/memory/tegra/mc.h index ddb16676c3af..01065f12ebeb 100644 --- a/drivers/memory/tegra/mc.h +++ b/drivers/memory/tegra/mc.h @@ -14,17 +14,39 @@ #include <soc/tegra/mc.h> +#define MC_INT_DECERR_MTS (1 << 16) +#define MC_INT_SECERR_SEC (1 << 13) +#define MC_INT_DECERR_VPR (1 << 12) +#define MC_INT_INVALID_APB_ASID_UPDATE (1 << 11) +#define MC_INT_INVALID_SMMU_PAGE (1 << 10) +#define MC_INT_ARBITRATION_EMEM (1 << 9) +#define MC_INT_SECURITY_VIOLATION (1 << 8) +#define MC_INT_INVALID_GART_PAGE (1 << 7) +#define MC_INT_DECERR_EMEM (1 << 6) + static inline u32 mc_readl(struct tegra_mc *mc, unsigned long offset) { + if (mc->regs2 && offset >= 0x24) + return readl(mc->regs2 + offset - 0x3c); + return readl(mc->regs + offset); } static inline void mc_writel(struct tegra_mc *mc, u32 value, unsigned long offset) { + if (mc->regs2 && offset >= 0x24) + return writel(value, mc->regs2 + offset - 0x3c); + writel(value, mc->regs + offset); } +extern const struct tegra_mc_reset_ops terga_mc_reset_ops_common; + +#ifdef CONFIG_ARCH_TEGRA_2x_SOC +extern const struct tegra_mc_soc tegra20_mc_soc; +#endif + #ifdef CONFIG_ARCH_TEGRA_3x_SOC extern const struct tegra_mc_soc tegra30_mc_soc; #endif diff --git a/drivers/memory/tegra/tegra114.c b/drivers/memory/tegra/tegra114.c index b20e6e3e208e..6560a5101322 100644 --- a/drivers/memory/tegra/tegra114.c +++ b/drivers/memory/tegra/tegra114.c @@ -938,6 +938,34 @@ static const struct tegra_smmu_soc tegra114_smmu_soc = { .num_asids = 4, }; +#define TEGRA114_MC_RESET(_name, _control, _status, _bit) \ + { \ + .name = #_name, \ + .id = TEGRA114_MC_RESET_##_name, \ + .control = _control, \ + .status = _status, \ + .bit = _bit, \ + } + +static const struct tegra_mc_reset tegra114_mc_resets[] = { + TEGRA114_MC_RESET(AVPC, 0x200, 0x204, 1), + TEGRA114_MC_RESET(DC, 0x200, 0x204, 2), + TEGRA114_MC_RESET(DCB, 0x200, 0x204, 3), + TEGRA114_MC_RESET(EPP, 0x200, 0x204, 4), + TEGRA114_MC_RESET(2D, 0x200, 0x204, 5), + TEGRA114_MC_RESET(HC, 0x200, 0x204, 6), + TEGRA114_MC_RESET(HDA, 0x200, 0x204, 7), + TEGRA114_MC_RESET(ISP, 0x200, 0x204, 8), + TEGRA114_MC_RESET(MPCORE, 0x200, 0x204, 9), + TEGRA114_MC_RESET(MPCORELP, 0x200, 0x204, 10), + TEGRA114_MC_RESET(MPE, 0x200, 0x204, 11), + TEGRA114_MC_RESET(3D, 0x200, 0x204, 12), + TEGRA114_MC_RESET(3D2, 0x200, 0x204, 13), + TEGRA114_MC_RESET(PPCS, 0x200, 0x204, 14), + TEGRA114_MC_RESET(VDE, 0x200, 0x204, 16), + TEGRA114_MC_RESET(VI, 0x200, 0x204, 17), +}; + const struct tegra_mc_soc tegra114_mc_soc = { .clients = tegra114_mc_clients, .num_clients = ARRAY_SIZE(tegra114_mc_clients), @@ -945,4 +973,9 @@ const struct tegra_mc_soc tegra114_mc_soc = { .atom_size = 32, .client_id_mask = 0x7f, .smmu = &tegra114_smmu_soc, + .intmask = MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION | + MC_INT_DECERR_EMEM, + .reset_ops = &terga_mc_reset_ops_common, + .resets = tegra114_mc_resets, + .num_resets = ARRAY_SIZE(tegra114_mc_resets), }; diff --git a/drivers/memory/tegra/tegra124.c b/drivers/memory/tegra/tegra124.c index 8b6360eabb8a..b561a1fe7f46 100644 --- a/drivers/memory/tegra/tegra124.c +++ b/drivers/memory/tegra/tegra124.c @@ -1012,6 +1012,42 @@ static const struct tegra_smmu_group_soc tegra124_groups[] = { }, }; +#define TEGRA124_MC_RESET(_name, _control, _status, _bit) \ + { \ + .name = #_name, \ + .id = TEGRA124_MC_RESET_##_name, \ + .control = _control, \ + .status = _status, \ + .bit = _bit, \ + } + +static const struct tegra_mc_reset tegra124_mc_resets[] = { + TEGRA124_MC_RESET(AFI, 0x200, 0x204, 0), + TEGRA124_MC_RESET(AVPC, 0x200, 0x204, 1), + TEGRA124_MC_RESET(DC, 0x200, 0x204, 2), + TEGRA124_MC_RESET(DCB, 0x200, 0x204, 3), + TEGRA124_MC_RESET(HC, 0x200, 0x204, 6), + TEGRA124_MC_RESET(HDA, 0x200, 0x204, 7), + TEGRA124_MC_RESET(ISP2, 0x200, 0x204, 8), + TEGRA124_MC_RESET(MPCORE, 0x200, 0x204, 9), + TEGRA124_MC_RESET(MPCORELP, 0x200, 0x204, 10), + TEGRA124_MC_RESET(MSENC, 0x200, 0x204, 11), + TEGRA124_MC_RESET(PPCS, 0x200, 0x204, 14), + TEGRA124_MC_RESET(SATA, 0x200, 0x204, 15), + TEGRA124_MC_RESET(VDE, 0x200, 0x204, 16), + TEGRA124_MC_RESET(VI, 0x200, 0x204, 17), + TEGRA124_MC_RESET(VIC, 0x200, 0x204, 18), + TEGRA124_MC_RESET(XUSB_HOST, 0x200, 0x204, 19), + TEGRA124_MC_RESET(XUSB_DEV, 0x200, 0x204, 20), + TEGRA124_MC_RESET(TSEC, 0x200, 0x204, 21), + TEGRA124_MC_RESET(SDMMC1, 0x200, 0x204, 22), + TEGRA124_MC_RESET(SDMMC2, 0x200, 0x204, 23), + TEGRA124_MC_RESET(SDMMC3, 0x200, 0x204, 25), + TEGRA124_MC_RESET(SDMMC4, 0x970, 0x974, 0), + TEGRA124_MC_RESET(ISP2B, 0x970, 0x974, 1), + TEGRA124_MC_RESET(GPU, 0x970, 0x974, 2), +}; + #ifdef CONFIG_ARCH_TEGRA_124_SOC static const struct tegra_smmu_soc tegra124_smmu_soc = { .clients = tegra124_mc_clients, @@ -1035,6 +1071,12 @@ const struct tegra_mc_soc tegra124_mc_soc = { .smmu = &tegra124_smmu_soc, .emem_regs = tegra124_mc_emem_regs, .num_emem_regs = ARRAY_SIZE(tegra124_mc_emem_regs), + .intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR | + MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE | + MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM, + .reset_ops = &terga_mc_reset_ops_common, + .resets = tegra124_mc_resets, + .num_resets = ARRAY_SIZE(tegra124_mc_resets), }; #endif /* CONFIG_ARCH_TEGRA_124_SOC */ @@ -1059,5 +1101,11 @@ const struct tegra_mc_soc tegra132_mc_soc = { .atom_size = 32, .client_id_mask = 0x7f, .smmu = &tegra132_smmu_soc, + .intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR | + MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE | + MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM, + .reset_ops = &terga_mc_reset_ops_common, + .resets = tegra124_mc_resets, + .num_resets = ARRAY_SIZE(tegra124_mc_resets), }; #endif /* CONFIG_ARCH_TEGRA_132_SOC */ diff --git a/drivers/memory/tegra/tegra20.c b/drivers/memory/tegra/tegra20.c new file mode 100644 index 000000000000..7119e532471c --- /dev/null +++ b/drivers/memory/tegra/tegra20.c @@ -0,0 +1,296 @@ +/* + * Copyright (C) 2012 NVIDIA CORPORATION. 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 version 2 as + * published by the Free Software Foundation. + */ + +#include <dt-bindings/memory/tegra20-mc.h> + +#include "mc.h" + +static const struct tegra_mc_client tegra20_mc_clients[] = { + { + .id = 0x00, + .name = "display0a", + }, { + .id = 0x01, + .name = "display0ab", + }, { + .id = 0x02, + .name = "display0b", + }, { + .id = 0x03, + .name = "display0bb", + }, { + .id = 0x04, + .name = "display0c", + }, { + .id = 0x05, + .name = "display0cb", + }, { + .id = 0x06, + .name = "display1b", + }, { + .id = 0x07, + .name = "display1bb", + }, { + .id = 0x08, + .name = "eppup", + }, { + .id = 0x09, + .name = "g2pr", + }, { + .id = 0x0a, + .name = "g2sr", + }, { + .id = 0x0b, + .name = "mpeunifbr", + }, { + .id = 0x0c, + .name = "viruv", + }, { + .id = 0x0d, + .name = "avpcarm7r", + }, { + .id = 0x0e, + .name = "displayhc", + }, { + .id = 0x0f, + .name = "displayhcb", + }, { + .id = 0x10, + .name = "fdcdrd", + }, { + .id = 0x11, + .name = "g2dr", + }, { + .id = 0x12, + .name = "host1xdmar", + }, { + .id = 0x13, + .name = "host1xr", + }, { + .id = 0x14, + .name = "idxsrd", + }, { + .id = 0x15, + .name = "mpcorer", + }, { + .id = 0x16, + .name = "mpe_ipred", + }, { + .id = 0x17, + .name = "mpeamemrd", + }, { + .id = 0x18, + .name = "mpecsrd", + }, { + .id = 0x19, + .name = "ppcsahbdmar", + }, { + .id = 0x1a, + .name = "ppcsahbslvr", + }, { + .id = 0x1b, + .name = "texsrd", + }, { + .id = 0x1c, + .name = "vdebsevr", + }, { + .id = 0x1d, + .name = "vdember", + }, { + .id = 0x1e, + .name = "vdemcer", + }, { + .id = 0x1f, + .name = "vdetper", + }, { + .id = 0x20, + .name = "eppu", + }, { + .id = 0x21, + .name = "eppv", + }, { + .id = 0x22, + .name = "eppy", + }, { + .id = 0x23, + .name = "mpeunifbw", + }, { + .id = 0x24, + .name = "viwsb", + }, { + .id = 0x25, + .name = "viwu", + }, { + .id = 0x26, + .name = "viwv", + }, { + .id = 0x27, + .name = "viwy", + }, { + .id = 0x28, + .name = "g2dw", + }, { + .id = 0x29, + .name = "avpcarm7w", + }, { + .id = 0x2a, + .name = "fdcdwr", + }, { + .id = 0x2b, + .name = "host1xw", + }, { + .id = 0x2c, + .name = "ispw", + }, { + .id = 0x2d, + .name = "mpcorew", + }, { + .id = 0x2e, + .name = "mpecswr", + }, { + .id = 0x2f, + .name = "ppcsahbdmaw", + }, { + .id = 0x30, + .name = "ppcsahbslvw", + }, { + .id = 0x31, + .name = "vdebsevw", + }, { + .id = 0x32, + .name = "vdembew", + }, { + .id = 0x33, + .name = "vdetpmw", + }, +}; + +#define TEGRA20_MC_RESET(_name, _control, _status, _reset, _bit) \ + { \ + .name = #_name, \ + .id = TEGRA20_MC_RESET_##_name, \ + .control = _control, \ + .status = _status, \ + .reset = _reset, \ + .bit = _bit, \ + } + +static const struct tegra_mc_reset tegra20_mc_resets[] = { + TEGRA20_MC_RESET(AVPC, 0x100, 0x140, 0x104, 0), + TEGRA20_MC_RESET(DC, 0x100, 0x144, 0x104, 1), + TEGRA20_MC_RESET(DCB, 0x100, 0x148, 0x104, 2), + TEGRA20_MC_RESET(EPP, 0x100, 0x14c, 0x104, 3), + TEGRA20_MC_RESET(2D, 0x100, 0x150, 0x104, 4), + TEGRA20_MC_RESET(HC, 0x100, 0x154, 0x104, 5), + TEGRA20_MC_RESET(ISP, 0x100, 0x158, 0x104, 6), + TEGRA20_MC_RESET(MPCORE, 0x100, 0x15c, 0x104, 7), + TEGRA20_MC_RESET(MPEA, 0x100, 0x160, 0x104, 8), + TEGRA20_MC_RESET(MPEB, 0x100, 0x164, 0x104, 9), + TEGRA20_MC_RESET(MPEC, 0x100, 0x168, 0x104, 10), + TEGRA20_MC_RESET(3D, 0x100, 0x16c, 0x104, 11), + TEGRA20_MC_RESET(PPCS, 0x100, 0x170, 0x104, 12), + TEGRA20_MC_RESET(VDE, 0x100, 0x174, 0x104, 13), + TEGRA20_MC_RESET(VI, 0x100, 0x178, 0x104, 14), +}; + +static int terga20_mc_hotreset_assert(struct tegra_mc *mc, + const struct tegra_mc_reset *rst) +{ + unsigned long flags; + u32 value; + + spin_lock_irqsave(&mc->lock, flags); + + value = mc_readl(mc, rst->reset); + mc_writel(mc, value & ~BIT(rst->bit), rst->reset); + + spin_unlock_irqrestore(&mc->lock, flags); + + return 0; +} + +static int terga20_mc_hotreset_deassert(struct tegra_mc *mc, + const struct tegra_mc_reset *rst) +{ + unsigned long flags; + u32 value; + + spin_lock_irqsave(&mc->lock, flags); + + value = mc_readl(mc, rst->reset); + mc_writel(mc, value | BIT(rst->bit), rst->reset); + + spin_unlock_irqrestore(&mc->lock, flags); + + return 0; +} + +static int terga20_mc_block_dma(struct tegra_mc *mc, + const struct tegra_mc_reset *rst) +{ + unsigned long flags; + u32 value; + + spin_lock_irqsave(&mc->lock, flags); + + value = mc_readl(mc, rst->control) & ~BIT(rst->bit); + mc_writel(mc, value, rst->control); + + spin_unlock_irqrestore(&mc->lock, flags); + + return 0; +} + +static bool terga20_mc_dma_idling(struct tegra_mc *mc, + const struct tegra_mc_reset *rst) +{ + return mc_readl(mc, rst->status) == 0; +} + +static int terga20_mc_reset_status(struct tegra_mc *mc, + const struct tegra_mc_reset *rst) +{ + return (mc_readl(mc, rst->reset) & BIT(rst->bit)) == 0; +} + +static int terga20_mc_unblock_dma(struct tegra_mc *mc, + const struct tegra_mc_reset *rst) +{ + unsigned long flags; + u32 value; + + spin_lock_irqsave(&mc->lock, flags); + + value = mc_readl(mc, rst->control) | BIT(rst->bit); + mc_writel(mc, value, rst->control); + + spin_unlock_irqrestore(&mc->lock, flags); + + return 0; +} + +const struct tegra_mc_reset_ops terga20_mc_reset_ops = { + .hotreset_assert = terga20_mc_hotreset_assert, + .hotreset_deassert = terga20_mc_hotreset_deassert, + .block_dma = terga20_mc_block_dma, + .dma_idling = terga20_mc_dma_idling, + .unblock_dma = terga20_mc_unblock_dma, + .reset_status = terga20_mc_reset_status, +}; + +const struct tegra_mc_soc tegra20_mc_soc = { + .clients = tegra20_mc_clients, + .num_clients = ARRAY_SIZE(tegra20_mc_clients), + .num_address_bits = 32, + .client_id_mask = 0x3f, + .intmask = MC_INT_SECURITY_VIOLATION | MC_INT_INVALID_GART_PAGE | + MC_INT_DECERR_EMEM, + .reset_ops = &terga20_mc_reset_ops, + .resets = tegra20_mc_resets, + .num_resets = ARRAY_SIZE(tegra20_mc_resets), +}; diff --git a/drivers/memory/tegra/tegra210.c b/drivers/memory/tegra/tegra210.c index d398bcd3fc57..d00a77160407 100644 --- a/drivers/memory/tegra/tegra210.c +++ b/drivers/memory/tegra/tegra210.c @@ -6,11 +6,6 @@ * published by the Free Software Foundation. */ -#include <linux/of.h> -#include <linux/mm.h> - -#include <asm/cacheflush.h> - #include <dt-bindings/memory/tegra210-mc.h> #include "mc.h" @@ -1085,6 +1080,48 @@ static const struct tegra_smmu_soc tegra210_smmu_soc = { .num_asids = 128, }; +#define TEGRA210_MC_RESET(_name, _control, _status, _bit) \ + { \ + .name = #_name, \ + .id = TEGRA210_MC_RESET_##_name, \ + .control = _control, \ + .status = _status, \ + .bit = _bit, \ + } + +static const struct tegra_mc_reset tegra210_mc_resets[] = { + TEGRA210_MC_RESET(AFI, 0x200, 0x204, 0), + TEGRA210_MC_RESET(AVPC, 0x200, 0x204, 1), + TEGRA210_MC_RESET(DC, 0x200, 0x204, 2), + TEGRA210_MC_RESET(DCB, 0x200, 0x204, 3), + TEGRA210_MC_RESET(HC, 0x200, 0x204, 6), + TEGRA210_MC_RESET(HDA, 0x200, 0x204, 7), + TEGRA210_MC_RESET(ISP2, 0x200, 0x204, 8), + TEGRA210_MC_RESET(MPCORE, 0x200, 0x204, 9), + TEGRA210_MC_RESET(NVENC, 0x200, 0x204, 11), + TEGRA210_MC_RESET(PPCS, 0x200, 0x204, 14), + TEGRA210_MC_RESET(SATA, 0x200, 0x204, 15), + TEGRA210_MC_RESET(VI, 0x200, 0x204, 17), + TEGRA210_MC_RESET(VIC, 0x200, 0x204, 18), + TEGRA210_MC_RESET(XUSB_HOST, 0x200, 0x204, 19), + TEGRA210_MC_RESET(XUSB_DEV, 0x200, 0x204, 20), + TEGRA210_MC_RESET(A9AVP, 0x200, 0x204, 21), + TEGRA210_MC_RESET(TSEC, 0x200, 0x204, 22), + TEGRA210_MC_RESET(SDMMC1, 0x200, 0x204, 29), + TEGRA210_MC_RESET(SDMMC2, 0x200, 0x204, 30), + TEGRA210_MC_RESET(SDMMC3, 0x200, 0x204, 31), + TEGRA210_MC_RESET(SDMMC4, 0x970, 0x974, 0), + TEGRA210_MC_RESET(ISP2B, 0x970, 0x974, 1), + TEGRA210_MC_RESET(GPU, 0x970, 0x974, 2), + TEGRA210_MC_RESET(NVDEC, 0x970, 0x974, 5), + TEGRA210_MC_RESET(APE, 0x970, 0x974, 6), + TEGRA210_MC_RESET(SE, 0x970, 0x974, 7), + TEGRA210_MC_RESET(NVJPG, 0x970, 0x974, 8), + TEGRA210_MC_RESET(AXIAP, 0x970, 0x974, 11), + TEGRA210_MC_RESET(ETR, 0x970, 0x974, 12), + TEGRA210_MC_RESET(TSECB, 0x970, 0x974, 13), +}; + const struct tegra_mc_soc tegra210_mc_soc = { .clients = tegra210_mc_clients, .num_clients = ARRAY_SIZE(tegra210_mc_clients), @@ -1092,4 +1129,10 @@ const struct tegra_mc_soc tegra210_mc_soc = { .atom_size = 64, .client_id_mask = 0xff, .smmu = &tegra210_smmu_soc, + .intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR | + MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE | + MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM, + .reset_ops = &terga_mc_reset_ops_common, + .resets = tegra210_mc_resets, + .num_resets = ARRAY_SIZE(tegra210_mc_resets), }; diff --git a/drivers/memory/tegra/tegra30.c b/drivers/memory/tegra/tegra30.c index d756c837f23e..bee5314ed404 100644 --- a/drivers/memory/tegra/tegra30.c +++ b/drivers/memory/tegra/tegra30.c @@ -960,6 +960,36 @@ static const struct tegra_smmu_soc tegra30_smmu_soc = { .num_asids = 4, }; +#define TEGRA30_MC_RESET(_name, _control, _status, _bit) \ + { \ + .name = #_name, \ + .id = TEGRA30_MC_RESET_##_name, \ + .control = _control, \ + .status = _status, \ + .bit = _bit, \ + } + +static const struct tegra_mc_reset tegra30_mc_resets[] = { + TEGRA30_MC_RESET(AFI, 0x200, 0x204, 0), + TEGRA30_MC_RESET(AVPC, 0x200, 0x204, 1), + TEGRA30_MC_RESET(DC, 0x200, 0x204, 2), + TEGRA30_MC_RESET(DCB, 0x200, 0x204, 3), + TEGRA30_MC_RESET(EPP, 0x200, 0x204, 4), + TEGRA30_MC_RESET(2D, 0x200, 0x204, 5), + TEGRA30_MC_RESET(HC, 0x200, 0x204, 6), + TEGRA30_MC_RESET(HDA, 0x200, 0x204, 7), + TEGRA30_MC_RESET(ISP, 0x200, 0x204, 8), + TEGRA30_MC_RESET(MPCORE, 0x200, 0x204, 9), + TEGRA30_MC_RESET(MPCORELP, 0x200, 0x204, 10), + TEGRA30_MC_RESET(MPE, 0x200, 0x204, 11), + TEGRA30_MC_RESET(3D, 0x200, 0x204, 12), + TEGRA30_MC_RESET(3D2, 0x200, 0x204, 13), + TEGRA30_MC_RESET(PPCS, 0x200, 0x204, 14), + TEGRA30_MC_RESET(SATA, 0x200, 0x204, 15), + TEGRA30_MC_RESET(VDE, 0x200, 0x204, 16), + TEGRA30_MC_RESET(VI, 0x200, 0x204, 17), +}; + const struct tegra_mc_soc tegra30_mc_soc = { .clients = tegra30_mc_clients, .num_clients = ARRAY_SIZE(tegra30_mc_clients), @@ -967,4 +997,9 @@ const struct tegra_mc_soc tegra30_mc_soc = { .atom_size = 16, .client_id_mask = 0x7f, .smmu = &tegra30_smmu_soc, + .intmask = MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION | + MC_INT_DECERR_EMEM, + .reset_ops = &terga_mc_reset_ops_common, + .resets = tegra30_mc_resets, + .num_resets = ARRAY_SIZE(tegra30_mc_resets), }; diff --git a/drivers/memory/tegra20-mc.c b/drivers/memory/tegra20-mc.c deleted file mode 100644 index cc309a05289a..000000000000 --- a/drivers/memory/tegra20-mc.c +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Tegra20 Memory Controller - * - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. - * - * 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. - */ - -#include <linux/err.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/ratelimit.h> -#include <linux/platform_device.h> -#include <linux/interrupt.h> -#include <linux/io.h> - -#define DRV_NAME "tegra20-mc" - -#define MC_INTSTATUS 0x0 -#define MC_INTMASK 0x4 - -#define MC_INT_ERR_SHIFT 6 -#define MC_INT_ERR_MASK (0x1f << MC_INT_ERR_SHIFT) -#define MC_INT_DECERR_EMEM BIT(MC_INT_ERR_SHIFT) -#define MC_INT_INVALID_GART_PAGE BIT(MC_INT_ERR_SHIFT + 1) -#define MC_INT_SECURITY_VIOLATION BIT(MC_INT_ERR_SHIFT + 2) -#define MC_INT_ARBITRATION_EMEM BIT(MC_INT_ERR_SHIFT + 3) - -#define MC_GART_ERROR_REQ 0x30 -#define MC_DECERR_EMEM_OTHERS_STATUS 0x58 -#define MC_SECURITY_VIOLATION_STATUS 0x74 - -#define SECURITY_VIOLATION_TYPE BIT(30) /* 0=TRUSTZONE, 1=CARVEOUT */ - -#define MC_CLIENT_ID_MASK 0x3f - -#define NUM_MC_REG_BANKS 2 - -struct tegra20_mc { - void __iomem *regs[NUM_MC_REG_BANKS]; - struct device *dev; -}; - -static inline u32 mc_readl(struct tegra20_mc *mc, u32 offs) -{ - u32 val = 0; - - if (offs < 0x24) - val = readl(mc->regs[0] + offs); - else if (offs < 0x400) - val = readl(mc->regs[1] + offs - 0x3c); - - return val; -} - -static inline void mc_writel(struct tegra20_mc *mc, u32 val, u32 offs) -{ - if (offs < 0x24) - writel(val, mc->regs[0] + offs); - else if (offs < 0x400) - writel(val, mc->regs[1] + offs - 0x3c); -} - -static const char * const tegra20_mc_client[] = { - "cbr_display0a", - "cbr_display0ab", - "cbr_display0b", - "cbr_display0bb", - "cbr_display0c", - "cbr_display0cb", - "cbr_display1b", - "cbr_display1bb", - "cbr_eppup", - "cbr_g2pr", - "cbr_g2sr", - "cbr_mpeunifbr", - "cbr_viruv", - "csr_avpcarm7r", - "csr_displayhc", - "csr_displayhcb", - "csr_fdcdrd", - "csr_g2dr", - "csr_host1xdmar", - "csr_host1xr", - "csr_idxsrd", - "csr_mpcorer", - "csr_mpe_ipred", - "csr_mpeamemrd", - "csr_mpecsrd", - "csr_ppcsahbdmar", - "csr_ppcsahbslvr", - "csr_texsrd", - "csr_vdebsevr", - "csr_vdember", - "csr_vdemcer", - "csr_vdetper", - "cbw_eppu", - "cbw_eppv", - "cbw_eppy", - "cbw_mpeunifbw", - "cbw_viwsb", - "cbw_viwu", - "cbw_viwv", - "cbw_viwy", - "ccw_g2dw", - "csw_avpcarm7w", - "csw_fdcdwr", - "csw_host1xw", - "csw_ispw", - "csw_mpcorew", - "csw_mpecswr", - "csw_ppcsahbdmaw", - "csw_ppcsahbslvw", - "csw_vdebsevw", - "csw_vdembew", - "csw_vdetpmw", -}; - -static void tegra20_mc_decode(struct tegra20_mc *mc, int n) -{ - u32 addr, req; - const char *client = "Unknown"; - int idx, cid; - const struct reg_info { - u32 offset; - u32 write_bit; /* 0=READ, 1=WRITE */ - int cid_shift; - char *message; - } reg[] = { - { - .offset = MC_DECERR_EMEM_OTHERS_STATUS, - .write_bit = 31, - .message = "MC_DECERR", - }, - { - .offset = MC_GART_ERROR_REQ, - .cid_shift = 1, - .message = "MC_GART_ERR", - - }, - { - .offset = MC_SECURITY_VIOLATION_STATUS, - .write_bit = 31, - .message = "MC_SECURITY_ERR", - }, - }; - - idx = n - MC_INT_ERR_SHIFT; - if ((idx < 0) || (idx >= ARRAY_SIZE(reg))) { - dev_err_ratelimited(mc->dev, "Unknown interrupt status %08lx\n", - BIT(n)); - return; - } - - req = mc_readl(mc, reg[idx].offset); - cid = (req >> reg[idx].cid_shift) & MC_CLIENT_ID_MASK; - if (cid < ARRAY_SIZE(tegra20_mc_client)) - client = tegra20_mc_client[cid]; - - addr = mc_readl(mc, reg[idx].offset + sizeof(u32)); - - dev_err_ratelimited(mc->dev, "%s (0x%08x): 0x%08x %s (%s %s)\n", - reg[idx].message, req, addr, client, - (req & BIT(reg[idx].write_bit)) ? "write" : "read", - (reg[idx].offset == MC_SECURITY_VIOLATION_STATUS) ? - ((req & SECURITY_VIOLATION_TYPE) ? - "carveout" : "trustzone") : ""); -} - -static const struct of_device_id tegra20_mc_of_match[] = { - { .compatible = "nvidia,tegra20-mc", }, - {}, -}; - -static irqreturn_t tegra20_mc_isr(int irq, void *data) -{ - u32 stat, mask, bit; - struct tegra20_mc *mc = data; - - stat = mc_readl(mc, MC_INTSTATUS); - mask = mc_readl(mc, MC_INTMASK); - mask &= stat; - if (!mask) - return IRQ_NONE; - while ((bit = ffs(mask)) != 0) { - tegra20_mc_decode(mc, bit - 1); - mask &= ~BIT(bit - 1); - } - - mc_writel(mc, stat, MC_INTSTATUS); - return IRQ_HANDLED; -} - -static int tegra20_mc_probe(struct platform_device *pdev) -{ - struct resource *irq; - struct tegra20_mc *mc; - int i, err; - u32 intmask; - - mc = devm_kzalloc(&pdev->dev, sizeof(*mc), GFP_KERNEL); - if (!mc) - return -ENOMEM; - mc->dev = &pdev->dev; - - for (i = 0; i < ARRAY_SIZE(mc->regs); i++) { - struct resource *res; - - res = platform_get_resource(pdev, IORESOURCE_MEM, i); - mc->regs[i] = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(mc->regs[i])) - return PTR_ERR(mc->regs[i]); - } - - irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!irq) - return -ENODEV; - err = devm_request_irq(&pdev->dev, irq->start, tegra20_mc_isr, - IRQF_SHARED, dev_name(&pdev->dev), mc); - if (err) - return -ENODEV; - - platform_set_drvdata(pdev, mc); - - intmask = MC_INT_INVALID_GART_PAGE | - MC_INT_DECERR_EMEM | MC_INT_SECURITY_VIOLATION; - mc_writel(mc, intmask, MC_INTMASK); - return 0; -} - -static struct platform_driver tegra20_mc_driver = { - .probe = tegra20_mc_probe, - .driver = { - .name = DRV_NAME, - .of_match_table = tegra20_mc_of_match, - }, -}; -module_platform_driver(tegra20_mc_driver); - -MODULE_AUTHOR("Hiroshi DOYU <hdoyu@nvidia.com>"); -MODULE_DESCRIPTION("Tegra20 MC driver"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/memory/ti-aemif.c b/drivers/memory/ti-aemif.c index 2744b1b91b57..31112f622b88 100644 --- a/drivers/memory/ti-aemif.c +++ b/drivers/memory/ti-aemif.c @@ -339,9 +339,6 @@ static int aemif_probe(struct platform_device *pdev) struct aemif_platform_data *pdata; struct of_dev_auxdata *dev_lookup; - if (np == NULL) - return 0; - aemif = devm_kzalloc(dev, sizeof(*aemif), GFP_KERNEL); if (!aemif) return -ENOMEM; @@ -363,8 +360,10 @@ static int aemif_probe(struct platform_device *pdev) aemif->clk_rate = clk_get_rate(aemif->clk) / MSEC_PER_SEC; - if (of_device_is_compatible(np, "ti,da850-aemif")) + if (np && of_device_is_compatible(np, "ti,da850-aemif")) aemif->cs_offset = 2; + else if (pdata) + aemif->cs_offset = pdata->cs_offset; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); aemif->base = devm_ioremap_resource(dev, res); @@ -373,15 +372,23 @@ static int aemif_probe(struct platform_device *pdev) goto error; } - /* - * For every controller device node, there is a cs device node that - * describe the bus configuration parameters. This functions iterate - * over these nodes and update the cs data array. - */ - for_each_available_child_of_node(np, child_np) { - ret = of_aemif_parse_abus_config(pdev, child_np); - if (ret < 0) - goto error; + if (np) { + /* + * For every controller device node, there is a cs device node + * that describe the bus configuration parameters. This + * functions iterate over these nodes and update the cs data + * array. + */ + for_each_available_child_of_node(np, child_np) { + ret = of_aemif_parse_abus_config(pdev, child_np); + if (ret < 0) + goto error; + } + } else if (pdata && pdata->num_abus_data > 0) { + for (i = 0; i < pdata->num_abus_data; i++, aemif->num_cs++) { + aemif->cs_data[i].cs = pdata->abus_data[i].cs; + aemif_get_hw_params(pdev, i); + } } for (i = 0; i < aemif->num_cs; i++) { @@ -394,14 +401,25 @@ static int aemif_probe(struct platform_device *pdev) } /* - * Create a child devices explicitly from here to - * guarantee that the child will be probed after the AEMIF timing - * parameters are set. + * Create a child devices explicitly from here to guarantee that the + * child will be probed after the AEMIF timing parameters are set. */ - for_each_available_child_of_node(np, child_np) { - ret = of_platform_populate(child_np, NULL, dev_lookup, dev); - if (ret < 0) - goto error; + if (np) { + for_each_available_child_of_node(np, child_np) { + ret = of_platform_populate(child_np, NULL, + dev_lookup, dev); + if (ret < 0) + goto error; + } + } else { + for (i = 0; i < pdata->num_sub_devices; i++) { + pdata->sub_devices[i].dev.parent = dev; + ret = platform_device_register(&pdata->sub_devices[i]); + if (ret) { + dev_warn(dev, "Error register sub device %s\n", + pdata->sub_devices[i].name); + } + } } return 0; @@ -422,7 +440,7 @@ static struct platform_driver aemif_driver = { .probe = aemif_probe, .remove = aemif_remove, .driver = { - .name = KBUILD_MODNAME, + .name = "ti-aemif", .of_match_table = of_match_ptr(aemif_of_match), }, }; diff --git a/drivers/memstick/core/ms_block.c b/drivers/memstick/core/ms_block.c index a15181fa45f7..716fc8ed31d3 100644 --- a/drivers/memstick/core/ms_block.c +++ b/drivers/memstick/core/ms_block.c @@ -1201,7 +1201,8 @@ static int msb_read_boot_blocks(struct msb_data *msb) dbg_verbose("Start of a scan for the boot blocks"); if (!msb->boot_page) { - page = kmalloc(sizeof(struct ms_boot_page)*2, GFP_KERNEL); + page = kmalloc_array(2, sizeof(struct ms_boot_page), + GFP_KERNEL); if (!page) return -ENOMEM; @@ -1341,7 +1342,8 @@ static int msb_ftl_initialize(struct msb_data *msb) msb->used_blocks_bitmap = kzalloc(msb->block_count / 8, GFP_KERNEL); msb->erased_blocks_bitmap = kzalloc(msb->block_count / 8, GFP_KERNEL); msb->lba_to_pba_table = - kmalloc(msb->logical_block_count * sizeof(u16), GFP_KERNEL); + kmalloc_array(msb->logical_block_count, sizeof(u16), + GFP_KERNEL); if (!msb->used_blocks_bitmap || !msb->lba_to_pba_table || !msb->erased_blocks_bitmap) { diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c index 4cbed4d06aa7..ebc00d47abf5 100644 --- a/drivers/message/fusion/mptlan.c +++ b/drivers/message/fusion/mptlan.c @@ -394,7 +394,8 @@ mpt_lan_open(struct net_device *dev) "a moment.\n"); } - priv->mpt_txfidx = kmalloc(priv->tx_max_out * sizeof(int), GFP_KERNEL); + priv->mpt_txfidx = kmalloc_array(priv->tx_max_out, sizeof(int), + GFP_KERNEL); if (priv->mpt_txfidx == NULL) goto out; priv->mpt_txfidx_tail = -1; @@ -408,8 +409,8 @@ mpt_lan_open(struct net_device *dev) dlprintk((KERN_INFO MYNAM "@lo: Finished initializing SendCtl\n")); - priv->mpt_rxfidx = kmalloc(priv->max_buckets_out * sizeof(int), - GFP_KERNEL); + priv->mpt_rxfidx = kmalloc_array(priv->max_buckets_out, sizeof(int), + GFP_KERNEL); if (priv->mpt_rxfidx == NULL) goto out_SendCtl; priv->mpt_rxfidx_tail = -1; diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index d9d2cf0d32ef..e9fd20dba18d 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -13,7 +13,6 @@ obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o obj-$(CONFIG_MFD_BCM590XX) += bcm590xx.o obj-$(CONFIG_MFD_BD9571MWV) += bd9571mwv.o cros_ec_core-objs := cros_ec.o -cros_ec_core-$(CONFIG_ACPI) += cros_ec_acpi_gpe.o obj-$(CONFIG_MFD_CROS_EC) += cros_ec_core.o obj-$(CONFIG_MFD_CROS_EC_I2C) += cros_ec_i2c.o obj-$(CONFIG_MFD_CROS_EC_SPI) += cros_ec_spi.o diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c index 8ba41073dd89..8d652b2f9d14 100644 --- a/drivers/mfd/ab8500-debugfs.c +++ b/drivers/mfd/ab8500-debugfs.c @@ -2519,11 +2519,10 @@ static ssize_t ab8500_subscribe_write(struct file *file, if (!dev_attr[irq_index]) return -ENOMEM; - event_name[irq_index] = kmalloc(count, GFP_KERNEL); + event_name[irq_index] = kasprintf(GFP_KERNEL, "%lu", user_val); if (!event_name[irq_index]) return -ENOMEM; - sprintf(event_name[irq_index], "%lu", user_val); dev_attr[irq_index]->show = show_irq; dev_attr[irq_index]->store = NULL; dev_attr[irq_index]->attr.name = event_name[irq_index]; @@ -2660,18 +2659,18 @@ static int ab8500_debug_probe(struct platform_device *plf) ab8500 = dev_get_drvdata(plf->dev.parent); num_irqs = ab8500->mask_size; - irq_count = devm_kzalloc(&plf->dev, - sizeof(*irq_count)*num_irqs, GFP_KERNEL); + irq_count = devm_kcalloc(&plf->dev, + num_irqs, sizeof(*irq_count), GFP_KERNEL); if (!irq_count) return -ENOMEM; - dev_attr = devm_kzalloc(&plf->dev, - sizeof(*dev_attr)*num_irqs, GFP_KERNEL); + dev_attr = devm_kcalloc(&plf->dev, + num_irqs, sizeof(*dev_attr), GFP_KERNEL); if (!dev_attr) return -ENOMEM; - event_name = devm_kzalloc(&plf->dev, - sizeof(*event_name)*num_irqs, GFP_KERNEL); + event_name = devm_kcalloc(&plf->dev, + num_irqs, sizeof(*event_name), GFP_KERNEL); if (!event_name) return -ENOMEM; diff --git a/drivers/mfd/abx500-core.c b/drivers/mfd/abx500-core.c index 0d3846a4767c..f282d39a5917 100644 --- a/drivers/mfd/abx500-core.c +++ b/drivers/mfd/abx500-core.c @@ -37,15 +37,12 @@ int abx500_register_ops(struct device *dev, struct abx500_ops *ops) { struct abx500_device_entry *dev_entry; - dev_entry = devm_kzalloc(dev, - sizeof(struct abx500_device_entry), - GFP_KERNEL); - if (!dev_entry) { - dev_err(dev, "register_ops kzalloc failed"); + dev_entry = devm_kzalloc(dev, sizeof(*dev_entry), GFP_KERNEL); + if (!dev_entry) return -ENOMEM; - } + dev_entry->dev = dev; - memcpy(&dev_entry->ops, ops, sizeof(struct abx500_ops)); + memcpy(&dev_entry->ops, ops, sizeof(*ops)); list_add_tail(&dev_entry->list, &abx500_list); return 0; @@ -68,7 +65,7 @@ int abx500_set_register_interruptible(struct device *dev, u8 bank, u8 reg, struct abx500_ops *ops; lookup_ops(dev->parent, &ops); - if ((ops != NULL) && (ops->set_register != NULL)) + if (ops && ops->set_register) return ops->set_register(dev, bank, reg, value); else return -ENOTSUPP; @@ -81,7 +78,7 @@ int abx500_get_register_interruptible(struct device *dev, u8 bank, u8 reg, struct abx500_ops *ops; lookup_ops(dev->parent, &ops); - if ((ops != NULL) && (ops->get_register != NULL)) + if (ops && ops->get_register) return ops->get_register(dev, bank, reg, value); else return -ENOTSUPP; @@ -94,7 +91,7 @@ int abx500_get_register_page_interruptible(struct device *dev, u8 bank, struct abx500_ops *ops; lookup_ops(dev->parent, &ops); - if ((ops != NULL) && (ops->get_register_page != NULL)) + if (ops && ops->get_register_page) return ops->get_register_page(dev, bank, first_reg, regvals, numregs); else @@ -108,7 +105,7 @@ int abx500_mask_and_set_register_interruptible(struct device *dev, u8 bank, struct abx500_ops *ops; lookup_ops(dev->parent, &ops); - if ((ops != NULL) && (ops->mask_and_set_register != NULL)) + if (ops && ops->mask_and_set_register) return ops->mask_and_set_register(dev, bank, reg, bitmask, bitvalues); else @@ -121,7 +118,7 @@ int abx500_get_chip_id(struct device *dev) struct abx500_ops *ops; lookup_ops(dev->parent, &ops); - if ((ops != NULL) && (ops->get_chip_id != NULL)) + if (ops && ops->get_chip_id) return ops->get_chip_id(dev); else return -ENOTSUPP; @@ -133,7 +130,7 @@ int abx500_event_registers_startup_state_get(struct device *dev, u8 *event) struct abx500_ops *ops; lookup_ops(dev->parent, &ops); - if ((ops != NULL) && (ops->event_registers_startup_state_get != NULL)) + if (ops && ops->event_registers_startup_state_get) return ops->event_registers_startup_state_get(dev, event); else return -ENOTSUPP; @@ -145,7 +142,7 @@ int abx500_startup_irq_enabled(struct device *dev, unsigned int irq) struct abx500_ops *ops; lookup_ops(dev->parent, &ops); - if ((ops != NULL) && (ops->startup_irq_enabled != NULL)) + if (ops && ops->startup_irq_enabled) return ops->startup_irq_enabled(dev, irq); else return -ENOTSUPP; diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index 77875250abe5..83f1c5a516d9 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c @@ -13,13 +13,12 @@ #include <linux/clk.h> #include <linux/delay.h> #include <linux/err.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/interrupt.h> #include <linux/mfd/core.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_device.h> -#include <linux/of_gpio.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> @@ -279,7 +278,7 @@ static int arizona_wait_for_boot(struct arizona *arizona) static inline void arizona_enable_reset(struct arizona *arizona) { if (arizona->pdata.reset) - gpio_set_value_cansleep(arizona->pdata.reset, 0); + gpiod_set_raw_value_cansleep(arizona->pdata.reset, 0); } static void arizona_disable_reset(struct arizona *arizona) @@ -295,7 +294,7 @@ static void arizona_disable_reset(struct arizona *arizona) break; } - gpio_set_value_cansleep(arizona->pdata.reset, 1); + gpiod_set_raw_value_cansleep(arizona->pdata.reset, 1); usleep_range(1000, 5000); } } @@ -799,14 +798,27 @@ static int arizona_of_get_core_pdata(struct arizona *arizona) struct arizona_pdata *pdata = &arizona->pdata; int ret, i; - pdata->reset = of_get_named_gpio(arizona->dev->of_node, "wlf,reset", 0); - if (pdata->reset == -EPROBE_DEFER) { - return pdata->reset; - } else if (pdata->reset < 0) { - dev_err(arizona->dev, "Reset GPIO missing/malformed: %d\n", - pdata->reset); + /* Handle old non-standard DT binding */ + pdata->reset = devm_gpiod_get_from_of_node(arizona->dev, + arizona->dev->of_node, + "wlf,reset", 0, + GPIOD_OUT_LOW, + "arizona /RESET"); + if (IS_ERR(pdata->reset)) { + ret = PTR_ERR(pdata->reset); - pdata->reset = 0; + /* + * Reset missing will be caught when other binding is read + * but all other errors imply this binding is in use but has + * encountered a problem so should be handled. + */ + if (ret == -EPROBE_DEFER) + return ret; + else if (ret != -ENOENT && ret != -ENOSYS) + dev_err(arizona->dev, "Reset GPIO malformed: %d\n", + ret); + + pdata->reset = NULL; } ret = of_property_read_u32_array(arizona->dev->of_node, @@ -1050,14 +1062,19 @@ int arizona_dev_init(struct arizona *arizona) goto err_early; } - if (arizona->pdata.reset) { + if (!arizona->pdata.reset) { /* Start out with /RESET low to put the chip into reset */ - ret = devm_gpio_request_one(arizona->dev, arizona->pdata.reset, - GPIOF_DIR_OUT | GPIOF_INIT_LOW, - "arizona /RESET"); - if (ret != 0) { - dev_err(dev, "Failed to request /RESET: %d\n", ret); - goto err_dcvdd; + arizona->pdata.reset = devm_gpiod_get(arizona->dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(arizona->pdata.reset)) { + ret = PTR_ERR(arizona->pdata.reset); + if (ret == -EPROBE_DEFER) + goto err_dcvdd; + + dev_err(arizona->dev, + "Reset GPIO missing/malformed: %d\n", ret); + + arizona->pdata.reset = NULL; } } diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index cf2e25ab2940..1531302a50ec 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -31,6 +31,8 @@ #include <linux/mfd/ds1wm.h> #include <linux/mfd/tmio.h> +#include <linux/mmc/host.h> + enum { ASIC3_CLOCK_SPI, ASIC3_CLOCK_OWM, @@ -719,6 +721,7 @@ static void asic3_mmc_clk_div(struct platform_device *pdev, int state) static struct tmio_mmc_data asic3_mmc_data = { .hclk = 24576000, + .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, .set_pwr = asic3_mmc_pwr, .set_clk_div = asic3_mmc_clk_div, }; diff --git a/drivers/mfd/atmel-smc.c b/drivers/mfd/atmel-smc.c index 7d77948567d7..0adbd2e796fe 100644 --- a/drivers/mfd/atmel-smc.c +++ b/drivers/mfd/atmel-smc.c @@ -12,6 +12,7 @@ */ #include <linux/mfd/syscon/atmel-smc.h> +#include <linux/string.h> /** * atmel_smc_cs_conf_init - initialize a SMC CS conf diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c index e94c72c2faa2..9a2ef3d9b8f8 100644 --- a/drivers/mfd/axp20x.c +++ b/drivers/mfd/axp20x.c @@ -169,131 +169,61 @@ static const struct regmap_access_table axp806_volatile_table = { .n_yes_ranges = ARRAY_SIZE(axp806_volatile_ranges), }; -static struct resource axp152_pek_resources[] = { +static const struct resource axp152_pek_resources[] = { DEFINE_RES_IRQ_NAMED(AXP152_IRQ_PEK_RIS_EDGE, "PEK_DBR"), DEFINE_RES_IRQ_NAMED(AXP152_IRQ_PEK_FAL_EDGE, "PEK_DBF"), }; -static struct resource axp20x_ac_power_supply_resources[] = { +static const struct resource axp20x_ac_power_supply_resources[] = { DEFINE_RES_IRQ_NAMED(AXP20X_IRQ_ACIN_PLUGIN, "ACIN_PLUGIN"), DEFINE_RES_IRQ_NAMED(AXP20X_IRQ_ACIN_REMOVAL, "ACIN_REMOVAL"), DEFINE_RES_IRQ_NAMED(AXP20X_IRQ_ACIN_OVER_V, "ACIN_OVER_V"), }; -static struct resource axp20x_pek_resources[] = { - { - .name = "PEK_DBR", - .start = AXP20X_IRQ_PEK_RIS_EDGE, - .end = AXP20X_IRQ_PEK_RIS_EDGE, - .flags = IORESOURCE_IRQ, - }, { - .name = "PEK_DBF", - .start = AXP20X_IRQ_PEK_FAL_EDGE, - .end = AXP20X_IRQ_PEK_FAL_EDGE, - .flags = IORESOURCE_IRQ, - }, +static const struct resource axp20x_pek_resources[] = { + DEFINE_RES_IRQ_NAMED(AXP20X_IRQ_PEK_RIS_EDGE, "PEK_DBR"), + DEFINE_RES_IRQ_NAMED(AXP20X_IRQ_PEK_FAL_EDGE, "PEK_DBF"), }; -static struct resource axp20x_usb_power_supply_resources[] = { +static const struct resource axp20x_usb_power_supply_resources[] = { DEFINE_RES_IRQ_NAMED(AXP20X_IRQ_VBUS_PLUGIN, "VBUS_PLUGIN"), DEFINE_RES_IRQ_NAMED(AXP20X_IRQ_VBUS_REMOVAL, "VBUS_REMOVAL"), DEFINE_RES_IRQ_NAMED(AXP20X_IRQ_VBUS_VALID, "VBUS_VALID"), DEFINE_RES_IRQ_NAMED(AXP20X_IRQ_VBUS_NOT_VALID, "VBUS_NOT_VALID"), }; -static struct resource axp22x_usb_power_supply_resources[] = { +static const struct resource axp22x_usb_power_supply_resources[] = { DEFINE_RES_IRQ_NAMED(AXP22X_IRQ_VBUS_PLUGIN, "VBUS_PLUGIN"), DEFINE_RES_IRQ_NAMED(AXP22X_IRQ_VBUS_REMOVAL, "VBUS_REMOVAL"), }; -static struct resource axp22x_pek_resources[] = { - { - .name = "PEK_DBR", - .start = AXP22X_IRQ_PEK_RIS_EDGE, - .end = AXP22X_IRQ_PEK_RIS_EDGE, - .flags = IORESOURCE_IRQ, - }, { - .name = "PEK_DBF", - .start = AXP22X_IRQ_PEK_FAL_EDGE, - .end = AXP22X_IRQ_PEK_FAL_EDGE, - .flags = IORESOURCE_IRQ, - }, +static const struct resource axp22x_pek_resources[] = { + DEFINE_RES_IRQ_NAMED(AXP22X_IRQ_PEK_RIS_EDGE, "PEK_DBR"), + DEFINE_RES_IRQ_NAMED(AXP22X_IRQ_PEK_FAL_EDGE, "PEK_DBF"), }; -static struct resource axp288_power_button_resources[] = { - { - .name = "PEK_DBR", - .start = AXP288_IRQ_POKP, - .end = AXP288_IRQ_POKP, - .flags = IORESOURCE_IRQ, - }, - { - .name = "PEK_DBF", - .start = AXP288_IRQ_POKN, - .end = AXP288_IRQ_POKN, - .flags = IORESOURCE_IRQ, - }, +static const struct resource axp288_power_button_resources[] = { + DEFINE_RES_IRQ_NAMED(AXP288_IRQ_POKP, "PEK_DBR"), + DEFINE_RES_IRQ_NAMED(AXP288_IRQ_POKN, "PEK_DBF"), }; -static struct resource axp288_fuel_gauge_resources[] = { - { - .start = AXP288_IRQ_QWBTU, - .end = AXP288_IRQ_QWBTU, - .flags = IORESOURCE_IRQ, - }, - { - .start = AXP288_IRQ_WBTU, - .end = AXP288_IRQ_WBTU, - .flags = IORESOURCE_IRQ, - }, - { - .start = AXP288_IRQ_QWBTO, - .end = AXP288_IRQ_QWBTO, - .flags = IORESOURCE_IRQ, - }, - { - .start = AXP288_IRQ_WBTO, - .end = AXP288_IRQ_WBTO, - .flags = IORESOURCE_IRQ, - }, - { - .start = AXP288_IRQ_WL2, - .end = AXP288_IRQ_WL2, - .flags = IORESOURCE_IRQ, - }, - { - .start = AXP288_IRQ_WL1, - .end = AXP288_IRQ_WL1, - .flags = IORESOURCE_IRQ, - }, +static const struct resource axp288_fuel_gauge_resources[] = { + DEFINE_RES_IRQ(AXP288_IRQ_QWBTU), + DEFINE_RES_IRQ(AXP288_IRQ_WBTU), + DEFINE_RES_IRQ(AXP288_IRQ_QWBTO), + DEFINE_RES_IRQ(AXP288_IRQ_WBTO), + DEFINE_RES_IRQ(AXP288_IRQ_WL2), + DEFINE_RES_IRQ(AXP288_IRQ_WL1), }; -static struct resource axp803_pek_resources[] = { - { - .name = "PEK_DBR", - .start = AXP803_IRQ_PEK_RIS_EDGE, - .end = AXP803_IRQ_PEK_RIS_EDGE, - .flags = IORESOURCE_IRQ, - }, { - .name = "PEK_DBF", - .start = AXP803_IRQ_PEK_FAL_EDGE, - .end = AXP803_IRQ_PEK_FAL_EDGE, - .flags = IORESOURCE_IRQ, - }, +static const struct resource axp803_pek_resources[] = { + DEFINE_RES_IRQ_NAMED(AXP803_IRQ_PEK_RIS_EDGE, "PEK_DBR"), + DEFINE_RES_IRQ_NAMED(AXP803_IRQ_PEK_FAL_EDGE, "PEK_DBF"), }; -static struct resource axp809_pek_resources[] = { - { - .name = "PEK_DBR", - .start = AXP809_IRQ_PEK_RIS_EDGE, - .end = AXP809_IRQ_PEK_RIS_EDGE, - .flags = IORESOURCE_IRQ, - }, { - .name = "PEK_DBF", - .start = AXP809_IRQ_PEK_FAL_EDGE, - .end = AXP809_IRQ_PEK_FAL_EDGE, - .flags = IORESOURCE_IRQ, - }, +static const struct resource axp809_pek_resources[] = { + DEFINE_RES_IRQ_NAMED(AXP809_IRQ_PEK_RIS_EDGE, "PEK_DBR"), + DEFINE_RES_IRQ_NAMED(AXP809_IRQ_PEK_FAL_EDGE, "PEK_DBF"), }; static const struct regmap_config axp152_regmap_config = { @@ -520,11 +450,11 @@ static const struct regmap_irq axp806_regmap_irqs[] = { INIT_REGMAP_IRQ(AXP806, DCDCC_V_LOW, 0, 5), INIT_REGMAP_IRQ(AXP806, DCDCD_V_LOW, 0, 6), INIT_REGMAP_IRQ(AXP806, DCDCE_V_LOW, 0, 7), - INIT_REGMAP_IRQ(AXP806, PWROK_LONG, 1, 0), - INIT_REGMAP_IRQ(AXP806, PWROK_SHORT, 1, 1), + INIT_REGMAP_IRQ(AXP806, POK_LONG, 1, 0), + INIT_REGMAP_IRQ(AXP806, POK_SHORT, 1, 1), INIT_REGMAP_IRQ(AXP806, WAKEUP, 1, 4), - INIT_REGMAP_IRQ(AXP806, PWROK_FALL, 1, 5), - INIT_REGMAP_IRQ(AXP806, PWROK_RISE, 1, 6), + INIT_REGMAP_IRQ(AXP806, POK_FALL, 1, 5), + INIT_REGMAP_IRQ(AXP806, POK_RISE, 1, 6), }; static const struct regmap_irq axp809_regmap_irqs[] = { @@ -648,7 +578,7 @@ static const struct regmap_irq_chip axp809_regmap_irq_chip = { .num_regs = 5, }; -static struct mfd_cell axp20x_cells[] = { +static const struct mfd_cell axp20x_cells[] = { { .name = "axp20x-gpio", .of_compatible = "x-powers,axp209-gpio", @@ -660,6 +590,7 @@ static struct mfd_cell axp20x_cells[] = { .name = "axp20x-regulator", }, { .name = "axp20x-adc", + .of_compatible = "x-powers,axp209-adc", }, { .name = "axp20x-battery-power-supply", .of_compatible = "x-powers,axp209-battery-power-supply", @@ -676,7 +607,7 @@ static struct mfd_cell axp20x_cells[] = { }, }; -static struct mfd_cell axp221_cells[] = { +static const struct mfd_cell axp221_cells[] = { { .name = "axp221-pek", .num_resources = ARRAY_SIZE(axp22x_pek_resources), @@ -684,7 +615,8 @@ static struct mfd_cell axp221_cells[] = { }, { .name = "axp20x-regulator", }, { - .name = "axp22x-adc" + .name = "axp22x-adc", + .of_compatible = "x-powers,axp221-adc", }, { .name = "axp20x-ac-power-supply", .of_compatible = "x-powers,axp221-ac-power-supply", @@ -701,13 +633,14 @@ static struct mfd_cell axp221_cells[] = { }, }; -static struct mfd_cell axp223_cells[] = { +static const struct mfd_cell axp223_cells[] = { { .name = "axp221-pek", .num_resources = ARRAY_SIZE(axp22x_pek_resources), .resources = axp22x_pek_resources, }, { .name = "axp22x-adc", + .of_compatible = "x-powers,axp221-adc", }, { .name = "axp20x-battery-power-supply", .of_compatible = "x-powers,axp221-battery-power-supply", @@ -726,7 +659,7 @@ static struct mfd_cell axp223_cells[] = { }, }; -static struct mfd_cell axp152_cells[] = { +static const struct mfd_cell axp152_cells[] = { { .name = "axp20x-pek", .num_resources = ARRAY_SIZE(axp152_pek_resources), @@ -734,87 +667,30 @@ static struct mfd_cell axp152_cells[] = { }, }; -static struct resource axp288_adc_resources[] = { - { - .name = "GPADC", - .start = AXP288_IRQ_GPADC, - .end = AXP288_IRQ_GPADC, - .flags = IORESOURCE_IRQ, - }, +static const struct resource axp288_adc_resources[] = { + DEFINE_RES_IRQ_NAMED(AXP288_IRQ_GPADC, "GPADC"), }; -static struct resource axp288_extcon_resources[] = { - { - .start = AXP288_IRQ_VBUS_FALL, - .end = AXP288_IRQ_VBUS_FALL, - .flags = IORESOURCE_IRQ, - }, - { - .start = AXP288_IRQ_VBUS_RISE, - .end = AXP288_IRQ_VBUS_RISE, - .flags = IORESOURCE_IRQ, - }, - { - .start = AXP288_IRQ_MV_CHNG, - .end = AXP288_IRQ_MV_CHNG, - .flags = IORESOURCE_IRQ, - }, - { - .start = AXP288_IRQ_BC_USB_CHNG, - .end = AXP288_IRQ_BC_USB_CHNG, - .flags = IORESOURCE_IRQ, - }, +static const struct resource axp288_extcon_resources[] = { + DEFINE_RES_IRQ(AXP288_IRQ_VBUS_FALL), + DEFINE_RES_IRQ(AXP288_IRQ_VBUS_RISE), + DEFINE_RES_IRQ(AXP288_IRQ_MV_CHNG), + DEFINE_RES_IRQ(AXP288_IRQ_BC_USB_CHNG), }; -static struct resource axp288_charger_resources[] = { - { - .start = AXP288_IRQ_OV, - .end = AXP288_IRQ_OV, - .flags = IORESOURCE_IRQ, - }, - { - .start = AXP288_IRQ_DONE, - .end = AXP288_IRQ_DONE, - .flags = IORESOURCE_IRQ, - }, - { - .start = AXP288_IRQ_CHARGING, - .end = AXP288_IRQ_CHARGING, - .flags = IORESOURCE_IRQ, - }, - { - .start = AXP288_IRQ_SAFE_QUIT, - .end = AXP288_IRQ_SAFE_QUIT, - .flags = IORESOURCE_IRQ, - }, - { - .start = AXP288_IRQ_SAFE_ENTER, - .end = AXP288_IRQ_SAFE_ENTER, - .flags = IORESOURCE_IRQ, - }, - { - .start = AXP288_IRQ_QCBTU, - .end = AXP288_IRQ_QCBTU, - .flags = IORESOURCE_IRQ, - }, - { - .start = AXP288_IRQ_CBTU, - .end = AXP288_IRQ_CBTU, - .flags = IORESOURCE_IRQ, - }, - { - .start = AXP288_IRQ_QCBTO, - .end = AXP288_IRQ_QCBTO, - .flags = IORESOURCE_IRQ, - }, - { - .start = AXP288_IRQ_CBTO, - .end = AXP288_IRQ_CBTO, - .flags = IORESOURCE_IRQ, - }, +static const struct resource axp288_charger_resources[] = { + DEFINE_RES_IRQ(AXP288_IRQ_OV), + DEFINE_RES_IRQ(AXP288_IRQ_DONE), + DEFINE_RES_IRQ(AXP288_IRQ_CHARGING), + DEFINE_RES_IRQ(AXP288_IRQ_SAFE_QUIT), + DEFINE_RES_IRQ(AXP288_IRQ_SAFE_ENTER), + DEFINE_RES_IRQ(AXP288_IRQ_QCBTU), + DEFINE_RES_IRQ(AXP288_IRQ_CBTU), + DEFINE_RES_IRQ(AXP288_IRQ_QCBTO), + DEFINE_RES_IRQ(AXP288_IRQ_CBTO), }; -static struct mfd_cell axp288_cells[] = { +static const struct mfd_cell axp288_cells[] = { { .name = "axp288_adc", .num_resources = ARRAY_SIZE(axp288_adc_resources), @@ -845,7 +721,7 @@ static struct mfd_cell axp288_cells[] = { }, }; -static struct mfd_cell axp803_cells[] = { +static const struct mfd_cell axp803_cells[] = { { .name = "axp221-pek", .num_resources = ARRAY_SIZE(axp803_pek_resources), @@ -854,14 +730,14 @@ static struct mfd_cell axp803_cells[] = { { .name = "axp20x-regulator" }, }; -static struct mfd_cell axp806_cells[] = { +static const struct mfd_cell axp806_cells[] = { { .id = 2, .name = "axp20x-regulator", }, }; -static struct mfd_cell axp809_cells[] = { +static const struct mfd_cell axp809_cells[] = { { .name = "axp221-pek", .num_resources = ARRAY_SIZE(axp809_pek_resources), @@ -872,7 +748,7 @@ static struct mfd_cell axp809_cells[] = { }, }; -static struct mfd_cell axp813_cells[] = { +static const struct mfd_cell axp813_cells[] = { { .name = "axp221-pek", .num_resources = ARRAY_SIZE(axp803_pek_resources), @@ -882,7 +758,13 @@ static struct mfd_cell axp813_cells[] = { }, { .name = "axp20x-gpio", .of_compatible = "x-powers,axp813-gpio", - } + }, { + .name = "axp813-adc", + .of_compatible = "x-powers,axp813-adc", + }, { + .name = "axp20x-battery-power-supply", + .of_compatible = "x-powers,axp813-battery-power-supply", + }, }; static struct axp20x_dev *axp20x_pm_power_off; diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c index 36156a41499c..65a9757a6d21 100644 --- a/drivers/mfd/cros_ec.c +++ b/drivers/mfd/cros_ec.c @@ -112,12 +112,16 @@ int cros_ec_register(struct cros_ec_device *ec_dev) mutex_init(&ec_dev->lock); - cros_ec_query_all(ec_dev); + err = cros_ec_query_all(ec_dev); + if (err) { + dev_err(dev, "Cannot identify the EC: error %d\n", err); + return err; + } if (ec_dev->irq) { - err = request_threaded_irq(ec_dev->irq, NULL, ec_irq_thread, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, - "chromeos-ec", ec_dev); + err = devm_request_threaded_irq(dev, ec_dev->irq, NULL, + ec_irq_thread, IRQF_TRIGGER_LOW | IRQF_ONESHOT, + "chromeos-ec", ec_dev); if (err) { dev_err(dev, "Failed to request IRQ %d: %d", ec_dev->irq, err); @@ -131,7 +135,7 @@ int cros_ec_register(struct cros_ec_device *ec_dev) dev_err(dev, "Failed to register Embedded Controller subdevice %d\n", err); - goto fail_mfd; + return err; } if (ec_dev->max_passthru) { @@ -149,7 +153,7 @@ int cros_ec_register(struct cros_ec_device *ec_dev) dev_err(dev, "Failed to register Power Delivery subdevice %d\n", err); - goto fail_mfd; + return err; } } @@ -158,7 +162,7 @@ int cros_ec_register(struct cros_ec_device *ec_dev) if (err) { mfd_remove_devices(dev); dev_err(dev, "Failed to register sub-devices\n"); - goto fail_mfd; + return err; } } @@ -173,14 +177,7 @@ int cros_ec_register(struct cros_ec_device *ec_dev) dev_info(dev, "Chrome EC device registered\n"); - cros_ec_acpi_install_gpe_handler(dev); - return 0; - -fail_mfd: - if (ec_dev->irq) - free_irq(ec_dev->irq, ec_dev); - return err; } EXPORT_SYMBOL(cros_ec_register); @@ -188,11 +185,6 @@ int cros_ec_remove(struct cros_ec_device *ec_dev) { mfd_remove_devices(ec_dev->dev); - cros_ec_acpi_remove_gpe_handler(); - - if (ec_dev->irq) - free_irq(ec_dev->irq, ec_dev); - return 0; } EXPORT_SYMBOL(cros_ec_remove); @@ -204,14 +196,9 @@ int cros_ec_suspend(struct cros_ec_device *ec_dev) int ret; u8 sleep_event; - if (!IS_ENABLED(CONFIG_ACPI) || pm_suspend_via_firmware()) { - sleep_event = HOST_SLEEP_EVENT_S3_SUSPEND; - } else { - sleep_event = HOST_SLEEP_EVENT_S0IX_SUSPEND; - - /* Clearing the GPE status for any pending event */ - cros_ec_acpi_clear_gpe(); - } + sleep_event = (!IS_ENABLED(CONFIG_ACPI) || pm_suspend_via_firmware()) ? + HOST_SLEEP_EVENT_S3_SUSPEND : + HOST_SLEEP_EVENT_S0IX_SUSPEND; ret = cros_ec_sleep_event(ec_dev, sleep_event); if (ret < 0) diff --git a/drivers/mfd/cros_ec_acpi_gpe.c b/drivers/mfd/cros_ec_acpi_gpe.c deleted file mode 100644 index 56d305dab2d4..000000000000 --- a/drivers/mfd/cros_ec_acpi_gpe.c +++ /dev/null @@ -1,103 +0,0 @@ -/* - * ChromeOS EC multi-function device - * - * Copyright (C) 2017 Google, Inc - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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. - * - * The ChromeOS EC multi function device is used to mux all the requests - * to the EC device for its multiple features: keyboard controller, - * battery charging and regulator control, firmware update. - */ -#include <linux/acpi.h> - -#define ACPI_LID_DEVICE "LID0" - -static int ec_wake_gpe = -EINVAL; - -/* - * This handler indicates to ACPI core that this GPE should stay enabled for - * lid to work in suspend to idle path. - */ -static u32 cros_ec_gpe_handler(acpi_handle gpe_device, u32 gpe_number, - void *data) -{ - return ACPI_INTERRUPT_HANDLED | ACPI_REENABLE_GPE; -} - -/* - * Get ACPI GPE for LID0 device. - */ -static int cros_ec_get_ec_wake_gpe(struct device *dev) -{ - struct acpi_device *cros_acpi_dev; - struct acpi_device *adev; - acpi_handle handle; - acpi_status status; - int ret; - - cros_acpi_dev = ACPI_COMPANION(dev); - - if (!cros_acpi_dev || !cros_acpi_dev->parent || - !cros_acpi_dev->parent->handle) - return -EINVAL; - - status = acpi_get_handle(cros_acpi_dev->parent->handle, ACPI_LID_DEVICE, - &handle); - if (ACPI_FAILURE(status)) - return -EINVAL; - - ret = acpi_bus_get_device(handle, &adev); - if (ret) - return ret; - - return adev->wakeup.gpe_number; -} - -int cros_ec_acpi_install_gpe_handler(struct device *dev) -{ - acpi_status status; - - ec_wake_gpe = cros_ec_get_ec_wake_gpe(dev); - - if (ec_wake_gpe < 0) - return ec_wake_gpe; - - status = acpi_install_gpe_handler(NULL, ec_wake_gpe, - ACPI_GPE_EDGE_TRIGGERED, - &cros_ec_gpe_handler, NULL); - if (ACPI_FAILURE(status)) - return -ENODEV; - - dev_info(dev, "Initialized, GPE = 0x%x\n", ec_wake_gpe); - - return 0; -} - -void cros_ec_acpi_remove_gpe_handler(void) -{ - acpi_status status; - - if (ec_wake_gpe < 0) - return; - - status = acpi_remove_gpe_handler(NULL, ec_wake_gpe, - &cros_ec_gpe_handler); - if (ACPI_FAILURE(status)) - pr_err("failed to remove gpe handler\n"); -} - -void cros_ec_acpi_clear_gpe(void) -{ - if (ec_wake_gpe < 0) - return; - - acpi_clear_gpe(NULL, ec_wake_gpe); -} diff --git a/drivers/mfd/cros_ec_dev.c b/drivers/mfd/cros_ec_dev.c index eafd06f62a3a..306e1fd109bd 100644 --- a/drivers/mfd/cros_ec_dev.c +++ b/drivers/mfd/cros_ec_dev.c @@ -113,10 +113,10 @@ static int cros_ec_check_features(struct cros_ec_dev *ec, int feature) dev_warn(ec->dev, "cannot get EC features: %d/%d\n", ret, msg->result); memset(ec->features, 0, sizeof(ec->features)); + } else { + memcpy(ec->features, msg->data, sizeof(ec->features)); } - memcpy(ec->features, msg->data, sizeof(ec->features)); - dev_dbg(ec->dev, "EC features %08x %08x\n", ec->features[0], ec->features[1]); @@ -262,13 +262,6 @@ static const struct file_operations fops = { #endif }; -static void __remove(struct device *dev) -{ - struct cros_ec_dev *ec = container_of(dev, struct cros_ec_dev, - class_dev); - kfree(ec); -} - static void cros_ec_sensors_register(struct cros_ec_dev *ec) { /* @@ -306,13 +299,14 @@ static void cros_ec_sensors_register(struct cros_ec_dev *ec) resp = (struct ec_response_motion_sense *)msg->data; sensor_num = resp->dump.sensor_count; /* Allocate 1 extra sensors in FIFO are needed */ - sensor_cells = kzalloc(sizeof(struct mfd_cell) * (sensor_num + 1), + sensor_cells = kcalloc(sensor_num + 1, sizeof(struct mfd_cell), GFP_KERNEL); if (sensor_cells == NULL) goto error; - sensor_platforms = kzalloc(sizeof(struct cros_ec_sensor_platform) * - (sensor_num + 1), GFP_KERNEL); + sensor_platforms = kcalloc(sensor_num + 1, + sizeof(struct cros_ec_sensor_platform), + GFP_KERNEL); if (sensor_platforms == NULL) goto error_platforms; @@ -383,12 +377,16 @@ error: kfree(msg); } +static const struct mfd_cell cros_ec_rtc_cells[] = { + { .name = "cros-ec-rtc" } +}; + static int ec_device_probe(struct platform_device *pdev) { int retval = -ENOMEM; struct device *dev = &pdev->dev; struct cros_ec_platform *ec_platform = dev_get_platdata(dev); - struct cros_ec_dev *ec = kzalloc(sizeof(*ec), GFP_KERNEL); + struct cros_ec_dev *ec = devm_kzalloc(dev, sizeof(*ec), GFP_KERNEL); if (!ec) return retval; @@ -410,7 +408,6 @@ static int ec_device_probe(struct platform_device *pdev) ec->class_dev.devt = MKDEV(ec_major, pdev->id); ec->class_dev.class = &cros_class; ec->class_dev.parent = dev; - ec->class_dev.release = __remove; retval = dev_set_name(&ec->class_dev, "%s", ec_platform->ec_name); if (retval) { @@ -422,6 +419,18 @@ static int ec_device_probe(struct platform_device *pdev) if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE)) cros_ec_sensors_register(ec); + /* Check whether this EC instance has RTC host command support */ + if (cros_ec_check_features(ec, EC_FEATURE_RTC)) { + retval = mfd_add_devices(ec->dev, PLATFORM_DEVID_AUTO, + cros_ec_rtc_cells, + ARRAY_SIZE(cros_ec_rtc_cells), + NULL, 0, NULL); + if (retval) + dev_err(ec->dev, + "failed to add cros-ec-rtc device: %d\n", + retval); + } + /* Take control of the lightbar from the EC. */ lb_manual_suspend_ctrl(ec, 1); @@ -456,9 +465,17 @@ static int ec_device_remove(struct platform_device *pdev) return 0; } +static void ec_device_shutdown(struct platform_device *pdev) +{ + struct cros_ec_dev *ec = dev_get_drvdata(&pdev->dev); + + /* Be sure to clear up debugfs delayed works */ + cros_ec_debugfs_remove(ec); +} + static const struct platform_device_id cros_ec_id[] = { { DRV_NAME, 0 }, - { /* sentinel */ }, + { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, cros_ec_id); @@ -466,6 +483,8 @@ static __maybe_unused int ec_device_suspend(struct device *dev) { struct cros_ec_dev *ec = dev_get_drvdata(dev); + cros_ec_debugfs_suspend(ec); + lb_suspend(ec); return 0; @@ -475,6 +494,8 @@ static __maybe_unused int ec_device_resume(struct device *dev) { struct cros_ec_dev *ec = dev_get_drvdata(dev); + cros_ec_debugfs_resume(ec); + lb_resume(ec); return 0; @@ -494,6 +515,7 @@ static struct platform_driver cros_ec_dev_driver = { }, .probe = ec_device_probe, .remove = ec_device_remove, + .shutdown = ec_device_shutdown, }; static int __init cros_ec_dev_init(void) diff --git a/drivers/mfd/cros_ec_i2c.c b/drivers/mfd/cros_ec_i2c.c index 9f70de1e4c70..ef9b4763356f 100644 --- a/drivers/mfd/cros_ec_i2c.c +++ b/drivers/mfd/cros_ec_i2c.c @@ -13,6 +13,7 @@ * GNU General Public License for more details. */ +#include <linux/acpi.h> #include <linux/delay.h> #include <linux/kernel.h> #include <linux/module.h> @@ -341,14 +342,17 @@ static int cros_ec_i2c_resume(struct device *dev) } #endif -static SIMPLE_DEV_PM_OPS(cros_ec_i2c_pm_ops, cros_ec_i2c_suspend, - cros_ec_i2c_resume); +static const struct dev_pm_ops cros_ec_i2c_pm_ops = { + SET_LATE_SYSTEM_SLEEP_PM_OPS(cros_ec_i2c_suspend, cros_ec_i2c_resume) +}; +#ifdef CONFIG_OF static const struct of_device_id cros_ec_i2c_of_match[] = { { .compatible = "google,cros-ec-i2c", }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, cros_ec_i2c_of_match); +#endif static const struct i2c_device_id cros_ec_i2c_id[] = { { "cros-ec-i2c", 0 }, @@ -356,9 +360,18 @@ static const struct i2c_device_id cros_ec_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, cros_ec_i2c_id); +#ifdef CONFIG_ACPI +static const struct acpi_device_id cros_ec_i2c_acpi_id[] = { + { "GOOG0008", 0 }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(acpi, cros_ec_i2c_acpi_id); +#endif + static struct i2c_driver cros_ec_driver = { .driver = { .name = "cros-ec-i2c", + .acpi_match_table = ACPI_PTR(cros_ec_i2c_acpi_id), .of_match_table = of_match_ptr(cros_ec_i2c_of_match), .pm = &cros_ec_i2c_pm_ops, }, diff --git a/drivers/mfd/da9062-core.c b/drivers/mfd/da9062-core.c index fe1811523e4a..9f6105906c09 100644 --- a/drivers/mfd/da9062-core.c +++ b/drivers/mfd/da9062-core.c @@ -365,186 +365,69 @@ static int da9062_get_device_type(struct da9062 *chip) } static const struct regmap_range da9061_aa_readable_ranges[] = { - { - .range_min = DA9062AA_PAGE_CON, - .range_max = DA9062AA_STATUS_B, - }, { - .range_min = DA9062AA_STATUS_D, - .range_max = DA9062AA_EVENT_C, - }, { - .range_min = DA9062AA_IRQ_MASK_A, - .range_max = DA9062AA_IRQ_MASK_C, - }, { - .range_min = DA9062AA_CONTROL_A, - .range_max = DA9062AA_GPIO_4, - }, { - .range_min = DA9062AA_GPIO_WKUP_MODE, - .range_max = DA9062AA_GPIO_OUT3_4, - }, { - .range_min = DA9062AA_BUCK1_CONT, - .range_max = DA9062AA_BUCK4_CONT, - }, { - .range_min = DA9062AA_BUCK3_CONT, - .range_max = DA9062AA_BUCK3_CONT, - }, { - .range_min = DA9062AA_LDO1_CONT, - .range_max = DA9062AA_LDO4_CONT, - }, { - .range_min = DA9062AA_DVC_1, - .range_max = DA9062AA_DVC_1, - }, { - .range_min = DA9062AA_SEQ, - .range_max = DA9062AA_ID_4_3, - }, { - .range_min = DA9062AA_ID_12_11, - .range_max = DA9062AA_ID_16_15, - }, { - .range_min = DA9062AA_ID_22_21, - .range_max = DA9062AA_ID_32_31, - }, { - .range_min = DA9062AA_SEQ_A, - .range_max = DA9062AA_WAIT, - }, { - .range_min = DA9062AA_RESET, - .range_max = DA9062AA_BUCK_ILIM_C, - }, { - .range_min = DA9062AA_BUCK1_CFG, - .range_max = DA9062AA_BUCK3_CFG, - }, { - .range_min = DA9062AA_VBUCK1_A, - .range_max = DA9062AA_VBUCK4_A, - }, { - .range_min = DA9062AA_VBUCK3_A, - .range_max = DA9062AA_VBUCK3_A, - }, { - .range_min = DA9062AA_VLDO1_A, - .range_max = DA9062AA_VLDO4_A, - }, { - .range_min = DA9062AA_VBUCK1_B, - .range_max = DA9062AA_VBUCK4_B, - }, { - .range_min = DA9062AA_VBUCK3_B, - .range_max = DA9062AA_VBUCK3_B, - }, { - .range_min = DA9062AA_VLDO1_B, - .range_max = DA9062AA_VLDO4_B, - }, { - .range_min = DA9062AA_INTERFACE, - .range_max = DA9062AA_CONFIG_E, - }, { - .range_min = DA9062AA_CONFIG_G, - .range_max = DA9062AA_CONFIG_K, - }, { - .range_min = DA9062AA_CONFIG_M, - .range_max = DA9062AA_CONFIG_M, - }, { - .range_min = DA9062AA_GP_ID_0, - .range_max = DA9062AA_GP_ID_19, - }, { - .range_min = DA9062AA_DEVICE_ID, - .range_max = DA9062AA_CONFIG_ID, - }, + regmap_reg_range(DA9062AA_PAGE_CON, DA9062AA_STATUS_B), + regmap_reg_range(DA9062AA_STATUS_D, DA9062AA_EVENT_C), + regmap_reg_range(DA9062AA_IRQ_MASK_A, DA9062AA_IRQ_MASK_C), + regmap_reg_range(DA9062AA_CONTROL_A, DA9062AA_GPIO_4), + regmap_reg_range(DA9062AA_GPIO_WKUP_MODE, DA9062AA_GPIO_OUT3_4), + regmap_reg_range(DA9062AA_BUCK1_CONT, DA9062AA_BUCK4_CONT), + regmap_reg_range(DA9062AA_BUCK3_CONT, DA9062AA_BUCK3_CONT), + regmap_reg_range(DA9062AA_LDO1_CONT, DA9062AA_LDO4_CONT), + regmap_reg_range(DA9062AA_DVC_1, DA9062AA_DVC_1), + regmap_reg_range(DA9062AA_SEQ, DA9062AA_ID_4_3), + regmap_reg_range(DA9062AA_ID_12_11, DA9062AA_ID_16_15), + regmap_reg_range(DA9062AA_ID_22_21, DA9062AA_ID_32_31), + regmap_reg_range(DA9062AA_SEQ_A, DA9062AA_WAIT), + regmap_reg_range(DA9062AA_RESET, DA9062AA_BUCK_ILIM_C), + regmap_reg_range(DA9062AA_BUCK1_CFG, DA9062AA_BUCK3_CFG), + regmap_reg_range(DA9062AA_VBUCK1_A, DA9062AA_VBUCK4_A), + regmap_reg_range(DA9062AA_VBUCK3_A, DA9062AA_VBUCK3_A), + regmap_reg_range(DA9062AA_VLDO1_A, DA9062AA_VLDO4_A), + regmap_reg_range(DA9062AA_VBUCK1_B, DA9062AA_VBUCK4_B), + regmap_reg_range(DA9062AA_VBUCK3_B, DA9062AA_VBUCK3_B), + regmap_reg_range(DA9062AA_VLDO1_B, DA9062AA_VLDO4_B), + regmap_reg_range(DA9062AA_INTERFACE, DA9062AA_CONFIG_E), + regmap_reg_range(DA9062AA_CONFIG_G, DA9062AA_CONFIG_K), + regmap_reg_range(DA9062AA_CONFIG_M, DA9062AA_CONFIG_M), + regmap_reg_range(DA9062AA_GP_ID_0, DA9062AA_GP_ID_19), + regmap_reg_range(DA9062AA_DEVICE_ID, DA9062AA_CONFIG_ID), }; static const struct regmap_range da9061_aa_writeable_ranges[] = { - { - .range_min = DA9062AA_PAGE_CON, - .range_max = DA9062AA_PAGE_CON, - }, { - .range_min = DA9062AA_FAULT_LOG, - .range_max = DA9062AA_EVENT_C, - }, { - .range_min = DA9062AA_IRQ_MASK_A, - .range_max = DA9062AA_IRQ_MASK_C, - }, { - .range_min = DA9062AA_CONTROL_A, - .range_max = DA9062AA_GPIO_4, - }, { - .range_min = DA9062AA_GPIO_WKUP_MODE, - .range_max = DA9062AA_GPIO_OUT3_4, - }, { - .range_min = DA9062AA_BUCK1_CONT, - .range_max = DA9062AA_BUCK4_CONT, - }, { - .range_min = DA9062AA_BUCK3_CONT, - .range_max = DA9062AA_BUCK3_CONT, - }, { - .range_min = DA9062AA_LDO1_CONT, - .range_max = DA9062AA_LDO4_CONT, - }, { - .range_min = DA9062AA_DVC_1, - .range_max = DA9062AA_DVC_1, - }, { - .range_min = DA9062AA_SEQ, - .range_max = DA9062AA_ID_4_3, - }, { - .range_min = DA9062AA_ID_12_11, - .range_max = DA9062AA_ID_16_15, - }, { - .range_min = DA9062AA_ID_22_21, - .range_max = DA9062AA_ID_32_31, - }, { - .range_min = DA9062AA_SEQ_A, - .range_max = DA9062AA_WAIT, - }, { - .range_min = DA9062AA_RESET, - .range_max = DA9062AA_BUCK_ILIM_C, - }, { - .range_min = DA9062AA_BUCK1_CFG, - .range_max = DA9062AA_BUCK3_CFG, - }, { - .range_min = DA9062AA_VBUCK1_A, - .range_max = DA9062AA_VBUCK4_A, - }, { - .range_min = DA9062AA_VBUCK3_A, - .range_max = DA9062AA_VBUCK3_A, - }, { - .range_min = DA9062AA_VLDO1_A, - .range_max = DA9062AA_VLDO4_A, - }, { - .range_min = DA9062AA_VBUCK1_B, - .range_max = DA9062AA_VBUCK4_B, - }, { - .range_min = DA9062AA_VBUCK3_B, - .range_max = DA9062AA_VBUCK3_B, - }, { - .range_min = DA9062AA_VLDO1_B, - .range_max = DA9062AA_VLDO4_B, - }, { - .range_min = DA9062AA_GP_ID_0, - .range_max = DA9062AA_GP_ID_19, - }, + regmap_reg_range(DA9062AA_PAGE_CON, DA9062AA_PAGE_CON), + regmap_reg_range(DA9062AA_FAULT_LOG, DA9062AA_EVENT_C), + regmap_reg_range(DA9062AA_IRQ_MASK_A, DA9062AA_IRQ_MASK_C), + regmap_reg_range(DA9062AA_CONTROL_A, DA9062AA_GPIO_4), + regmap_reg_range(DA9062AA_GPIO_WKUP_MODE, DA9062AA_GPIO_OUT3_4), + regmap_reg_range(DA9062AA_BUCK1_CONT, DA9062AA_BUCK4_CONT), + regmap_reg_range(DA9062AA_BUCK3_CONT, DA9062AA_BUCK3_CONT), + regmap_reg_range(DA9062AA_LDO1_CONT, DA9062AA_LDO4_CONT), + regmap_reg_range(DA9062AA_DVC_1, DA9062AA_DVC_1), + regmap_reg_range(DA9062AA_SEQ, DA9062AA_ID_4_3), + regmap_reg_range(DA9062AA_ID_12_11, DA9062AA_ID_16_15), + regmap_reg_range(DA9062AA_ID_22_21, DA9062AA_ID_32_31), + regmap_reg_range(DA9062AA_SEQ_A, DA9062AA_WAIT), + regmap_reg_range(DA9062AA_RESET, DA9062AA_BUCK_ILIM_C), + regmap_reg_range(DA9062AA_BUCK1_CFG, DA9062AA_BUCK3_CFG), + regmap_reg_range(DA9062AA_VBUCK1_A, DA9062AA_VBUCK4_A), + regmap_reg_range(DA9062AA_VBUCK3_A, DA9062AA_VBUCK3_A), + regmap_reg_range(DA9062AA_VLDO1_A, DA9062AA_VLDO4_A), + regmap_reg_range(DA9062AA_VBUCK1_B, DA9062AA_VBUCK4_B), + regmap_reg_range(DA9062AA_VBUCK3_B, DA9062AA_VBUCK3_B), + regmap_reg_range(DA9062AA_VLDO1_B, DA9062AA_VLDO4_B), + regmap_reg_range(DA9062AA_GP_ID_0, DA9062AA_GP_ID_19), }; static const struct regmap_range da9061_aa_volatile_ranges[] = { - { - .range_min = DA9062AA_PAGE_CON, - .range_max = DA9062AA_STATUS_B, - }, { - .range_min = DA9062AA_STATUS_D, - .range_max = DA9062AA_EVENT_C, - }, { - .range_min = DA9062AA_CONTROL_A, - .range_max = DA9062AA_CONTROL_B, - }, { - .range_min = DA9062AA_CONTROL_E, - .range_max = DA9062AA_CONTROL_F, - }, { - .range_min = DA9062AA_BUCK1_CONT, - .range_max = DA9062AA_BUCK4_CONT, - }, { - .range_min = DA9062AA_BUCK3_CONT, - .range_max = DA9062AA_BUCK3_CONT, - }, { - .range_min = DA9062AA_LDO1_CONT, - .range_max = DA9062AA_LDO4_CONT, - }, { - .range_min = DA9062AA_DVC_1, - .range_max = DA9062AA_DVC_1, - }, { - .range_min = DA9062AA_SEQ, - .range_max = DA9062AA_SEQ, - }, + regmap_reg_range(DA9062AA_PAGE_CON, DA9062AA_STATUS_B), + regmap_reg_range(DA9062AA_STATUS_D, DA9062AA_EVENT_C), + regmap_reg_range(DA9062AA_CONTROL_A, DA9062AA_CONTROL_B), + regmap_reg_range(DA9062AA_CONTROL_E, DA9062AA_CONTROL_F), + regmap_reg_range(DA9062AA_BUCK1_CONT, DA9062AA_BUCK4_CONT), + regmap_reg_range(DA9062AA_BUCK3_CONT, DA9062AA_BUCK3_CONT), + regmap_reg_range(DA9062AA_LDO1_CONT, DA9062AA_LDO4_CONT), + regmap_reg_range(DA9062AA_DVC_1, DA9062AA_DVC_1), + regmap_reg_range(DA9062AA_SEQ, DA9062AA_SEQ), }; static const struct regmap_access_table da9061_aa_readable_table = { @@ -587,186 +470,69 @@ static struct regmap_config da9061_regmap_config = { }; static const struct regmap_range da9062_aa_readable_ranges[] = { - { - .range_min = DA9062AA_PAGE_CON, - .range_max = DA9062AA_STATUS_B, - }, { - .range_min = DA9062AA_STATUS_D, - .range_max = DA9062AA_EVENT_C, - }, { - .range_min = DA9062AA_IRQ_MASK_A, - .range_max = DA9062AA_IRQ_MASK_C, - }, { - .range_min = DA9062AA_CONTROL_A, - .range_max = DA9062AA_GPIO_4, - }, { - .range_min = DA9062AA_GPIO_WKUP_MODE, - .range_max = DA9062AA_BUCK4_CONT, - }, { - .range_min = DA9062AA_BUCK3_CONT, - .range_max = DA9062AA_BUCK3_CONT, - }, { - .range_min = DA9062AA_LDO1_CONT, - .range_max = DA9062AA_LDO4_CONT, - }, { - .range_min = DA9062AA_DVC_1, - .range_max = DA9062AA_DVC_1, - }, { - .range_min = DA9062AA_COUNT_S, - .range_max = DA9062AA_SECOND_D, - }, { - .range_min = DA9062AA_SEQ, - .range_max = DA9062AA_ID_4_3, - }, { - .range_min = DA9062AA_ID_12_11, - .range_max = DA9062AA_ID_16_15, - }, { - .range_min = DA9062AA_ID_22_21, - .range_max = DA9062AA_ID_32_31, - }, { - .range_min = DA9062AA_SEQ_A, - .range_max = DA9062AA_BUCK3_CFG, - }, { - .range_min = DA9062AA_VBUCK2_A, - .range_max = DA9062AA_VBUCK4_A, - }, { - .range_min = DA9062AA_VBUCK3_A, - .range_max = DA9062AA_VBUCK3_A, - }, { - .range_min = DA9062AA_VLDO1_A, - .range_max = DA9062AA_VLDO4_A, - }, { - .range_min = DA9062AA_VBUCK2_B, - .range_max = DA9062AA_VBUCK4_B, - }, { - .range_min = DA9062AA_VBUCK3_B, - .range_max = DA9062AA_VBUCK3_B, - }, { - .range_min = DA9062AA_VLDO1_B, - .range_max = DA9062AA_VLDO4_B, - }, { - .range_min = DA9062AA_BBAT_CONT, - .range_max = DA9062AA_BBAT_CONT, - }, { - .range_min = DA9062AA_INTERFACE, - .range_max = DA9062AA_CONFIG_E, - }, { - .range_min = DA9062AA_CONFIG_G, - .range_max = DA9062AA_CONFIG_K, - }, { - .range_min = DA9062AA_CONFIG_M, - .range_max = DA9062AA_CONFIG_M, - }, { - .range_min = DA9062AA_TRIM_CLDR, - .range_max = DA9062AA_GP_ID_19, - }, { - .range_min = DA9062AA_DEVICE_ID, - .range_max = DA9062AA_CONFIG_ID, - }, + regmap_reg_range(DA9062AA_PAGE_CON, DA9062AA_STATUS_B), + regmap_reg_range(DA9062AA_STATUS_D, DA9062AA_EVENT_C), + regmap_reg_range(DA9062AA_IRQ_MASK_A, DA9062AA_IRQ_MASK_C), + regmap_reg_range(DA9062AA_CONTROL_A, DA9062AA_GPIO_4), + regmap_reg_range(DA9062AA_GPIO_WKUP_MODE, DA9062AA_BUCK4_CONT), + regmap_reg_range(DA9062AA_BUCK3_CONT, DA9062AA_BUCK3_CONT), + regmap_reg_range(DA9062AA_LDO1_CONT, DA9062AA_LDO4_CONT), + regmap_reg_range(DA9062AA_DVC_1, DA9062AA_DVC_1), + regmap_reg_range(DA9062AA_COUNT_S, DA9062AA_SECOND_D), + regmap_reg_range(DA9062AA_SEQ, DA9062AA_ID_4_3), + regmap_reg_range(DA9062AA_ID_12_11, DA9062AA_ID_16_15), + regmap_reg_range(DA9062AA_ID_22_21, DA9062AA_ID_32_31), + regmap_reg_range(DA9062AA_SEQ_A, DA9062AA_BUCK3_CFG), + regmap_reg_range(DA9062AA_VBUCK2_A, DA9062AA_VBUCK4_A), + regmap_reg_range(DA9062AA_VBUCK3_A, DA9062AA_VBUCK3_A), + regmap_reg_range(DA9062AA_VLDO1_A, DA9062AA_VLDO4_A), + regmap_reg_range(DA9062AA_VBUCK2_B, DA9062AA_VBUCK4_B), + regmap_reg_range(DA9062AA_VBUCK3_B, DA9062AA_VBUCK3_B), + regmap_reg_range(DA9062AA_VLDO1_B, DA9062AA_VLDO4_B), + regmap_reg_range(DA9062AA_BBAT_CONT, DA9062AA_BBAT_CONT), + regmap_reg_range(DA9062AA_INTERFACE, DA9062AA_CONFIG_E), + regmap_reg_range(DA9062AA_CONFIG_G, DA9062AA_CONFIG_K), + regmap_reg_range(DA9062AA_CONFIG_M, DA9062AA_CONFIG_M), + regmap_reg_range(DA9062AA_TRIM_CLDR, DA9062AA_GP_ID_19), + regmap_reg_range(DA9062AA_DEVICE_ID, DA9062AA_CONFIG_ID), }; static const struct regmap_range da9062_aa_writeable_ranges[] = { - { - .range_min = DA9062AA_PAGE_CON, - .range_max = DA9062AA_PAGE_CON, - }, { - .range_min = DA9062AA_FAULT_LOG, - .range_max = DA9062AA_EVENT_C, - }, { - .range_min = DA9062AA_IRQ_MASK_A, - .range_max = DA9062AA_IRQ_MASK_C, - }, { - .range_min = DA9062AA_CONTROL_A, - .range_max = DA9062AA_GPIO_4, - }, { - .range_min = DA9062AA_GPIO_WKUP_MODE, - .range_max = DA9062AA_BUCK4_CONT, - }, { - .range_min = DA9062AA_BUCK3_CONT, - .range_max = DA9062AA_BUCK3_CONT, - }, { - .range_min = DA9062AA_LDO1_CONT, - .range_max = DA9062AA_LDO4_CONT, - }, { - .range_min = DA9062AA_DVC_1, - .range_max = DA9062AA_DVC_1, - }, { - .range_min = DA9062AA_COUNT_S, - .range_max = DA9062AA_ALARM_Y, - }, { - .range_min = DA9062AA_SEQ, - .range_max = DA9062AA_ID_4_3, - }, { - .range_min = DA9062AA_ID_12_11, - .range_max = DA9062AA_ID_16_15, - }, { - .range_min = DA9062AA_ID_22_21, - .range_max = DA9062AA_ID_32_31, - }, { - .range_min = DA9062AA_SEQ_A, - .range_max = DA9062AA_BUCK3_CFG, - }, { - .range_min = DA9062AA_VBUCK2_A, - .range_max = DA9062AA_VBUCK4_A, - }, { - .range_min = DA9062AA_VBUCK3_A, - .range_max = DA9062AA_VBUCK3_A, - }, { - .range_min = DA9062AA_VLDO1_A, - .range_max = DA9062AA_VLDO4_A, - }, { - .range_min = DA9062AA_VBUCK2_B, - .range_max = DA9062AA_VBUCK4_B, - }, { - .range_min = DA9062AA_VBUCK3_B, - .range_max = DA9062AA_VBUCK3_B, - }, { - .range_min = DA9062AA_VLDO1_B, - .range_max = DA9062AA_VLDO4_B, - }, { - .range_min = DA9062AA_BBAT_CONT, - .range_max = DA9062AA_BBAT_CONT, - }, { - .range_min = DA9062AA_GP_ID_0, - .range_max = DA9062AA_GP_ID_19, - }, + regmap_reg_range(DA9062AA_PAGE_CON, DA9062AA_PAGE_CON), + regmap_reg_range(DA9062AA_FAULT_LOG, DA9062AA_EVENT_C), + regmap_reg_range(DA9062AA_IRQ_MASK_A, DA9062AA_IRQ_MASK_C), + regmap_reg_range(DA9062AA_CONTROL_A, DA9062AA_GPIO_4), + regmap_reg_range(DA9062AA_GPIO_WKUP_MODE, DA9062AA_BUCK4_CONT), + regmap_reg_range(DA9062AA_BUCK3_CONT, DA9062AA_BUCK3_CONT), + regmap_reg_range(DA9062AA_LDO1_CONT, DA9062AA_LDO4_CONT), + regmap_reg_range(DA9062AA_DVC_1, DA9062AA_DVC_1), + regmap_reg_range(DA9062AA_COUNT_S, DA9062AA_ALARM_Y), + regmap_reg_range(DA9062AA_SEQ, DA9062AA_ID_4_3), + regmap_reg_range(DA9062AA_ID_12_11, DA9062AA_ID_16_15), + regmap_reg_range(DA9062AA_ID_22_21, DA9062AA_ID_32_31), + regmap_reg_range(DA9062AA_SEQ_A, DA9062AA_BUCK3_CFG), + regmap_reg_range(DA9062AA_VBUCK2_A, DA9062AA_VBUCK4_A), + regmap_reg_range(DA9062AA_VBUCK3_A, DA9062AA_VBUCK3_A), + regmap_reg_range(DA9062AA_VLDO1_A, DA9062AA_VLDO4_A), + regmap_reg_range(DA9062AA_VBUCK2_B, DA9062AA_VBUCK4_B), + regmap_reg_range(DA9062AA_VBUCK3_B, DA9062AA_VBUCK3_B), + regmap_reg_range(DA9062AA_VLDO1_B, DA9062AA_VLDO4_B), + regmap_reg_range(DA9062AA_BBAT_CONT, DA9062AA_BBAT_CONT), + regmap_reg_range(DA9062AA_GP_ID_0, DA9062AA_GP_ID_19), }; static const struct regmap_range da9062_aa_volatile_ranges[] = { - { - .range_min = DA9062AA_PAGE_CON, - .range_max = DA9062AA_STATUS_B, - }, { - .range_min = DA9062AA_STATUS_D, - .range_max = DA9062AA_EVENT_C, - }, { - .range_min = DA9062AA_CONTROL_A, - .range_max = DA9062AA_CONTROL_B, - }, { - .range_min = DA9062AA_CONTROL_E, - .range_max = DA9062AA_CONTROL_F, - }, { - .range_min = DA9062AA_BUCK2_CONT, - .range_max = DA9062AA_BUCK4_CONT, - }, { - .range_min = DA9062AA_BUCK3_CONT, - .range_max = DA9062AA_BUCK3_CONT, - }, { - .range_min = DA9062AA_LDO1_CONT, - .range_max = DA9062AA_LDO4_CONT, - }, { - .range_min = DA9062AA_DVC_1, - .range_max = DA9062AA_DVC_1, - }, { - .range_min = DA9062AA_COUNT_S, - .range_max = DA9062AA_SECOND_D, - }, { - .range_min = DA9062AA_SEQ, - .range_max = DA9062AA_SEQ, - }, { - .range_min = DA9062AA_EN_32K, - .range_max = DA9062AA_EN_32K, - }, + regmap_reg_range(DA9062AA_PAGE_CON, DA9062AA_STATUS_B), + regmap_reg_range(DA9062AA_STATUS_D, DA9062AA_EVENT_C), + regmap_reg_range(DA9062AA_CONTROL_A, DA9062AA_CONTROL_B), + regmap_reg_range(DA9062AA_CONTROL_E, DA9062AA_CONTROL_F), + regmap_reg_range(DA9062AA_BUCK2_CONT, DA9062AA_BUCK4_CONT), + regmap_reg_range(DA9062AA_BUCK3_CONT, DA9062AA_BUCK3_CONT), + regmap_reg_range(DA9062AA_LDO1_CONT, DA9062AA_LDO4_CONT), + regmap_reg_range(DA9062AA_DVC_1, DA9062AA_DVC_1), + regmap_reg_range(DA9062AA_COUNT_S, DA9062AA_SECOND_D), + regmap_reg_range(DA9062AA_SEQ, DA9062AA_SEQ), + regmap_reg_range(DA9062AA_EN_32K, DA9062AA_EN_32K), }; static const struct regmap_access_table da9062_aa_readable_table = { diff --git a/drivers/mfd/htc-i2cpld.c b/drivers/mfd/htc-i2cpld.c index 3f9eee5f8fb9..01572b5e79e8 100644 --- a/drivers/mfd/htc-i2cpld.c +++ b/drivers/mfd/htc-i2cpld.c @@ -477,12 +477,12 @@ static int htcpld_setup_chips(struct platform_device *pdev) /* Setup each chip's output GPIOs */ htcpld->nchips = pdata->num_chip; - htcpld->chip = devm_kzalloc(dev, sizeof(struct htcpld_chip) * htcpld->nchips, + htcpld->chip = devm_kcalloc(dev, + htcpld->nchips, + sizeof(struct htcpld_chip), GFP_KERNEL); - if (!htcpld->chip) { - dev_warn(dev, "Unable to allocate memory for chips\n"); + if (!htcpld->chip) return -ENOMEM; - } /* Add the chips as best we can */ for (i = 0; i < htcpld->nchips; i++) { diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c index d1c46de89eb4..d9ae983095c5 100644 --- a/drivers/mfd/intel-lpss-pci.c +++ b/drivers/mfd/intel-lpss-pci.c @@ -124,6 +124,11 @@ static const struct intel_lpss_platform_info apl_i2c_info = { .properties = apl_i2c_properties, }; +static const struct intel_lpss_platform_info cnl_i2c_info = { + .clk_rate = 216000000, + .properties = spt_i2c_properties, +}; + static const struct pci_device_id intel_lpss_pci_ids[] = { /* BXT A-Step */ { PCI_VDEVICE(INTEL, 0x0aac), (kernel_ulong_t)&bxt_i2c_info }, @@ -207,13 +212,13 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x9daa), (kernel_ulong_t)&spt_info }, { PCI_VDEVICE(INTEL, 0x9dab), (kernel_ulong_t)&spt_info }, { PCI_VDEVICE(INTEL, 0x9dfb), (kernel_ulong_t)&spt_info }, - { PCI_VDEVICE(INTEL, 0x9dc5), (kernel_ulong_t)&spt_i2c_info }, - { PCI_VDEVICE(INTEL, 0x9dc6), (kernel_ulong_t)&spt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x9dc5), (kernel_ulong_t)&cnl_i2c_info }, + { PCI_VDEVICE(INTEL, 0x9dc6), (kernel_ulong_t)&cnl_i2c_info }, { PCI_VDEVICE(INTEL, 0x9dc7), (kernel_ulong_t)&spt_uart_info }, - { PCI_VDEVICE(INTEL, 0x9de8), (kernel_ulong_t)&spt_i2c_info }, - { PCI_VDEVICE(INTEL, 0x9de9), (kernel_ulong_t)&spt_i2c_info }, - { PCI_VDEVICE(INTEL, 0x9dea), (kernel_ulong_t)&spt_i2c_info }, - { PCI_VDEVICE(INTEL, 0x9deb), (kernel_ulong_t)&spt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x9de8), (kernel_ulong_t)&cnl_i2c_info }, + { PCI_VDEVICE(INTEL, 0x9de9), (kernel_ulong_t)&cnl_i2c_info }, + { PCI_VDEVICE(INTEL, 0x9dea), (kernel_ulong_t)&cnl_i2c_info }, + { PCI_VDEVICE(INTEL, 0x9deb), (kernel_ulong_t)&cnl_i2c_info }, /* SPT-H */ { PCI_VDEVICE(INTEL, 0xa127), (kernel_ulong_t)&spt_uart_info }, { PCI_VDEVICE(INTEL, 0xa128), (kernel_ulong_t)&spt_uart_info }, @@ -240,10 +245,10 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { { PCI_VDEVICE(INTEL, 0xa32b), (kernel_ulong_t)&spt_info }, { PCI_VDEVICE(INTEL, 0xa37b), (kernel_ulong_t)&spt_info }, { PCI_VDEVICE(INTEL, 0xa347), (kernel_ulong_t)&spt_uart_info }, - { PCI_VDEVICE(INTEL, 0xa368), (kernel_ulong_t)&spt_i2c_info }, - { PCI_VDEVICE(INTEL, 0xa369), (kernel_ulong_t)&spt_i2c_info }, - { PCI_VDEVICE(INTEL, 0xa36a), (kernel_ulong_t)&spt_i2c_info }, - { PCI_VDEVICE(INTEL, 0xa36b), (kernel_ulong_t)&spt_i2c_info }, + { PCI_VDEVICE(INTEL, 0xa368), (kernel_ulong_t)&cnl_i2c_info }, + { PCI_VDEVICE(INTEL, 0xa369), (kernel_ulong_t)&cnl_i2c_info }, + { PCI_VDEVICE(INTEL, 0xa36a), (kernel_ulong_t)&cnl_i2c_info }, + { PCI_VDEVICE(INTEL, 0xa36b), (kernel_ulong_t)&cnl_i2c_info }, { } }; MODULE_DEVICE_TABLE(pci, intel_lpss_pci_ids); diff --git a/drivers/mfd/intel-lpss.c b/drivers/mfd/intel-lpss.c index 9e545eb6e8b4..50bffc3382d7 100644 --- a/drivers/mfd/intel-lpss.c +++ b/drivers/mfd/intel-lpss.c @@ -40,8 +40,8 @@ /* Offsets from lpss->priv */ #define LPSS_PRIV_RESETS 0x04 -#define LPSS_PRIV_RESETS_FUNC BIT(2) -#define LPSS_PRIV_RESETS_IDMA 0x3 +#define LPSS_PRIV_RESETS_IDMA BIT(2) +#define LPSS_PRIV_RESETS_FUNC 0x3 #define LPSS_PRIV_ACTIVELTR 0x10 #define LPSS_PRIV_IDLELTR 0x14 @@ -275,11 +275,11 @@ static void intel_lpss_init_dev(const struct intel_lpss *lpss) intel_lpss_deassert_reset(lpss); + intel_lpss_set_remap_addr(lpss); + if (!intel_lpss_has_idma(lpss)) return; - intel_lpss_set_remap_addr(lpss); - /* Make sure that SPI multiblock DMA transfers are re-enabled */ if (lpss->type == LPSS_DEV_SPI) writel(value, lpss->priv + LPSS_PRIV_SSP_REG); diff --git a/drivers/mfd/janz-cmodio.c b/drivers/mfd/janz-cmodio.c index ec1f46a6be3a..317a47ad5bb7 100644 --- a/drivers/mfd/janz-cmodio.c +++ b/drivers/mfd/janz-cmodio.c @@ -183,10 +183,8 @@ static int cmodio_pci_probe(struct pci_dev *dev, int ret; priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) { - dev_err(&dev->dev, "unable to allocate private data\n"); + if (!priv) return -ENOMEM; - } pci_set_drvdata(dev, priv); priv->pdev = dev; diff --git a/drivers/mfd/jz4740-adc.c b/drivers/mfd/jz4740-adc.c index 798e44306382..f4cd14294b61 100644 --- a/drivers/mfd/jz4740-adc.c +++ b/drivers/mfd/jz4740-adc.c @@ -212,10 +212,8 @@ static int jz4740_adc_probe(struct platform_device *pdev) int irq_base; adc = devm_kzalloc(&pdev->dev, sizeof(*adc), GFP_KERNEL); - if (!adc) { - dev_err(&pdev->dev, "Failed to allocate driver structure\n"); + if (!adc) return -ENOMEM; - } adc->irq = platform_get_irq(pdev, 0); if (adc->irq < 0) { diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c index 2d6e2c392786..3f554c447521 100644 --- a/drivers/mfd/max8997.c +++ b/drivers/mfd/max8997.c @@ -148,10 +148,8 @@ static struct max8997_platform_data *max8997_i2c_parse_dt_pdata( struct max8997_platform_data *pd; pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); - if (!pd) { - dev_err(dev, "could not allocate memory for pdata\n"); + if (!pd) return ERR_PTR(-ENOMEM); - } pd->ono = irq_of_parse_and_map(dev->of_node, 1); diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index c57e407020f1..94e3f32ce935 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -158,7 +158,7 @@ static int mfd_add_device(struct device *parent, int id, if (!pdev) goto fail_alloc; - res = kzalloc(sizeof(*res) * cell->num_resources, GFP_KERNEL); + res = kcalloc(cell->num_resources, sizeof(*res), GFP_KERNEL); if (!res) goto fail_device; diff --git a/drivers/mfd/motorola-cpcap.c b/drivers/mfd/motorola-cpcap.c index d2cc1eabac05..5276911caaec 100644 --- a/drivers/mfd/motorola-cpcap.c +++ b/drivers/mfd/motorola-cpcap.c @@ -173,9 +173,9 @@ static int cpcap_init_irq(struct cpcap_ddata *cpcap) int ret; cpcap->irqs = devm_kzalloc(&cpcap->spi->dev, - sizeof(*cpcap->irqs) * - CPCAP_NR_IRQ_REG_BANKS * - cpcap->regmap_conf->val_bits, + array3_size(sizeof(*cpcap->irqs), + CPCAP_NR_IRQ_REG_BANKS, + cpcap->regmap_conf->val_bits), GFP_KERNEL); if (!cpcap->irqs) return -ENOMEM; diff --git a/drivers/mfd/mt6397-core.c b/drivers/mfd/mt6397-core.c index 04a601f6aebe..77b64bd64df3 100644 --- a/drivers/mfd/mt6397-core.c +++ b/drivers/mfd/mt6397-core.c @@ -43,6 +43,16 @@ static const struct resource mt6397_rtc_resources[] = { }, }; +static const struct resource mt6323_keys_resources[] = { + DEFINE_RES_IRQ(MT6323_IRQ_STATUS_PWRKEY), + DEFINE_RES_IRQ(MT6323_IRQ_STATUS_FCHRKEY), +}; + +static const struct resource mt6397_keys_resources[] = { + DEFINE_RES_IRQ(MT6397_IRQ_PWRKEY), + DEFINE_RES_IRQ(MT6397_IRQ_HOMEKEY), +}; + static const struct mfd_cell mt6323_devs[] = { { .name = "mt6323-regulator", @@ -50,6 +60,11 @@ static const struct mfd_cell mt6323_devs[] = { }, { .name = "mt6323-led", .of_compatible = "mediatek,mt6323-led" + }, { + .name = "mtk-pmic-keys", + .num_resources = ARRAY_SIZE(mt6323_keys_resources), + .resources = mt6323_keys_resources, + .of_compatible = "mediatek,mt6323-keys" }, }; @@ -71,7 +86,12 @@ static const struct mfd_cell mt6397_devs[] = { }, { .name = "mt6397-pinctrl", .of_compatible = "mediatek,mt6397-pinctrl", - }, + }, { + .name = "mtk-pmic-keys", + .num_resources = ARRAY_SIZE(mt6397_keys_resources), + .resources = mt6397_keys_resources, + .of_compatible = "mediatek,mt6397-keys" + } }; static void mt6397_irq_lock(struct irq_data *data) @@ -289,7 +309,7 @@ static int mt6397_probe(struct platform_device *pdev) ret = devm_mfd_add_devices(&pdev->dev, -1, mt6323_devs, ARRAY_SIZE(mt6323_devs), NULL, - 0, NULL); + 0, pmic->irq_domain); break; case MT6397_CID_CODE: @@ -304,7 +324,7 @@ static int mt6397_probe(struct platform_device *pdev) ret = devm_mfd_add_devices(&pdev->dev, -1, mt6397_devs, ARRAY_SIZE(mt6397_devs), NULL, - 0, NULL); + 0, pmic->irq_domain); break; default: diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 7aab376ecb84..e11ab12fbdf2 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -153,27 +153,6 @@ static const char * const port_modes[] = { [OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM] = "ohci-tll-2pin-dpdm", }; -/** - * omap_usbhs_get_dt_port_mode - Get the 'enum usbhs_omap_port_mode' - * from the port mode string. - * @mode: The port mode string, usually obtained from device tree. - * - * The function returns the 'enum usbhs_omap_port_mode' that matches the - * provided port mode string as per the port_modes table. - * If no match is found it returns -ENODEV - */ -static int omap_usbhs_get_dt_port_mode(const char *mode) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(port_modes); i++) { - if (!strcmp(mode, port_modes[i])) - return i; - } - - return -ENODEV; -} - static struct platform_device *omap_usbhs_alloc_child(const char *name, struct resource *res, int num_resources, void *pdata, size_t pdata_size, struct device *dev) @@ -529,7 +508,8 @@ static int usbhs_omap_get_dt_pdata(struct device *dev, if (ret < 0) continue; - ret = omap_usbhs_get_dt_port_mode(mode); + /* get 'enum usbhs_omap_port_mode' from port mode string */ + ret = match_string(port_modes, ARRAY_SIZE(port_modes), mode); if (ret < 0) { dev_warn(dev, "Invalid port%d-mode \"%s\" in device tree\n", i, mode); diff --git a/drivers/mfd/omap-usb-tll.c b/drivers/mfd/omap-usb-tll.c index 44a5d66314c6..446713dbee27 100644 --- a/drivers/mfd/omap-usb-tll.c +++ b/drivers/mfd/omap-usb-tll.c @@ -108,9 +108,9 @@ (x) != OMAP_EHCI_PORT_MODE_PHY) struct usbtll_omap { - int nch; /* num. of channels */ - struct clk **ch_clk; - void __iomem *base; + void __iomem *base; + int nch; /* num. of channels */ + struct clk *ch_clk[0]; /* must be the last member */ }; /*-------------------------------------------------------------------------*/ @@ -216,53 +216,49 @@ static int usbtll_omap_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct resource *res; struct usbtll_omap *tll; - int ret = 0; - int i, ver; + void __iomem *base; + int i, nch, ver; dev_dbg(dev, "starting TI HSUSB TLL Controller\n"); - tll = devm_kzalloc(dev, sizeof(struct usbtll_omap), GFP_KERNEL); - if (!tll) { - dev_err(dev, "Memory allocation failed\n"); - return -ENOMEM; - } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - tll->base = devm_ioremap_resource(dev, res); - if (IS_ERR(tll->base)) - return PTR_ERR(tll->base); + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); - platform_set_drvdata(pdev, tll); pm_runtime_enable(dev); pm_runtime_get_sync(dev); - ver = usbtll_read(tll->base, OMAP_USBTLL_REVISION); + ver = usbtll_read(base, OMAP_USBTLL_REVISION); switch (ver) { case OMAP_USBTLL_REV1: case OMAP_USBTLL_REV4: - tll->nch = OMAP_TLL_CHANNEL_COUNT; + nch = OMAP_TLL_CHANNEL_COUNT; break; case OMAP_USBTLL_REV2: case OMAP_USBTLL_REV3: - tll->nch = OMAP_REV2_TLL_CHANNEL_COUNT; + nch = OMAP_REV2_TLL_CHANNEL_COUNT; break; default: - tll->nch = OMAP_TLL_CHANNEL_COUNT; - dev_dbg(dev, - "USB TLL Rev : 0x%x not recognized, assuming %d channels\n", - ver, tll->nch); + nch = OMAP_TLL_CHANNEL_COUNT; + dev_dbg(dev, "rev 0x%x not recognized, assuming %d channels\n", + ver, nch); break; } - tll->ch_clk = devm_kzalloc(dev, sizeof(struct clk *) * tll->nch, - GFP_KERNEL); - if (!tll->ch_clk) { - ret = -ENOMEM; - dev_err(dev, "Couldn't allocate memory for channel clocks\n"); - goto err_clk_alloc; + tll = devm_kzalloc(dev, sizeof(*tll) + sizeof(tll->ch_clk[nch]), + GFP_KERNEL); + if (!tll) { + pm_runtime_put_sync(dev); + pm_runtime_disable(dev); + return -ENOMEM; } - for (i = 0; i < tll->nch; i++) { + tll->base = base; + tll->nch = nch; + platform_set_drvdata(pdev, tll); + + for (i = 0; i < nch; i++) { char clkname[] = "usb_tll_hs_usb_chx_clk"; snprintf(clkname, sizeof(clkname), @@ -282,12 +278,6 @@ static int usbtll_omap_probe(struct platform_device *pdev) spin_unlock(&tll_lock); return 0; - -err_clk_alloc: - pm_runtime_put_sync(dev); - pm_runtime_disable(dev); - - return ret; } /** diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c index f952dff6765f..0d2a88d53eed 100644 --- a/drivers/mfd/pcf50633-core.c +++ b/drivers/mfd/pcf50633-core.c @@ -242,8 +242,10 @@ static int pcf50633_probe(struct i2c_client *client, for (i = 0; i < PCF50633_NUM_REGULATORS; i++) { pdev = platform_device_alloc("pcf50633-regulator", i); - if (!pdev) - return -ENOMEM; + if (!pdev) { + ret = -ENOMEM; + goto err2; + } pdev->dev.parent = pcf->dev; ret = platform_device_add_data(pdev, &pdata->reg_init_data[i], @@ -269,6 +271,7 @@ static int pcf50633_probe(struct i2c_client *client, err: platform_device_put(pdev); +err2: for (j = 0; j < i; j++) platform_device_put(pcf->regulator_pdev[j]); diff --git a/drivers/mfd/qcom-spmi-pmic.c b/drivers/mfd/qcom-spmi-pmic.c index 2022bdfa7ab4..e2e95de649a4 100644 --- a/drivers/mfd/qcom-spmi-pmic.c +++ b/drivers/mfd/qcom-spmi-pmic.c @@ -39,6 +39,9 @@ #define PM8916_SUBTYPE 0x0b #define PM8004_SUBTYPE 0x0c #define PM8909_SUBTYPE 0x0d +#define PM8998_SUBTYPE 0x14 +#define PMI8998_SUBTYPE 0x15 +#define PM8005_SUBTYPE 0x18 static const struct of_device_id pmic_spmi_id_table[] = { { .compatible = "qcom,spmi-pmic", .data = (void *)COMMON_SUBTYPE }, @@ -55,6 +58,9 @@ static const struct of_device_id pmic_spmi_id_table[] = { { .compatible = "qcom,pm8916", .data = (void *)PM8916_SUBTYPE }, { .compatible = "qcom,pm8004", .data = (void *)PM8004_SUBTYPE }, { .compatible = "qcom,pm8909", .data = (void *)PM8909_SUBTYPE }, + { .compatible = "qcom,pm8998", .data = (void *)PM8998_SUBTYPE }, + { .compatible = "qcom,pmi8998", .data = (void *)PMI8998_SUBTYPE }, + { .compatible = "qcom,pm8005", .data = (void *)PM8005_SUBTYPE }, { } }; diff --git a/drivers/mfd/rave-sp.c b/drivers/mfd/rave-sp.c index 5c858e784a89..36dcd98977d6 100644 --- a/drivers/mfd/rave-sp.c +++ b/drivers/mfd/rave-sp.c @@ -45,7 +45,9 @@ #define RAVE_SP_DLE 0x10 #define RAVE_SP_MAX_DATA_SIZE 64 -#define RAVE_SP_CHECKSUM_SIZE 2 /* Worst case scenario on RDU2 */ +#define RAVE_SP_CHECKSUM_8B2C 1 +#define RAVE_SP_CHECKSUM_CCITT 2 +#define RAVE_SP_CHECKSUM_SIZE RAVE_SP_CHECKSUM_CCITT /* * We don't store STX, ETX and unescaped bytes, so Rx is only * DATA + CSUM @@ -160,6 +162,8 @@ struct rave_sp_variant { * @variant: Device variant specific information * @event_notifier_list: Input event notification chain * + * @part_number_firmware: Firmware version + * @part_number_bootloader: Bootloader version */ struct rave_sp { struct serdev_device *serdev; @@ -171,8 +175,40 @@ struct rave_sp { const struct rave_sp_variant *variant; struct blocking_notifier_head event_notifier_list; + + const char *part_number_firmware; + const char *part_number_bootloader; }; +struct rave_sp_version { + u8 hardware; + __le16 major; + u8 minor; + u8 letter[2]; +} __packed; + +struct rave_sp_status { + struct rave_sp_version bootloader_version; + struct rave_sp_version firmware_version; + u16 rdu_eeprom_flag; + u16 dds_eeprom_flag; + u8 pic_flag; + u8 orientation; + u32 etc; + s16 temp[2]; + u8 backlight_current[3]; + u8 dip_switch; + u8 host_interrupt; + u16 voltage_28; + u8 i2c_device_status; + u8 power_status; + u8 general_status; + u8 deprecated1; + u8 power_led_status; + u8 deprecated2; + u8 periph_power_shutoff; +} __packed; + static bool rave_sp_id_is_event(u8 code) { return (code & 0xF0) == RAVE_SP_EVNT_BASE; @@ -275,8 +311,8 @@ static int rave_sp_write(struct rave_sp *sp, const u8 *data, u8 data_size) length = dest - frame; - print_hex_dump(KERN_DEBUG, "rave-sp tx: ", DUMP_PREFIX_NONE, - 16, 1, frame, length, false); + print_hex_dump_debug("rave-sp tx: ", DUMP_PREFIX_NONE, + 16, 1, frame, length, false); return serdev_device_write(sp->serdev, frame, length, HZ); } @@ -415,10 +451,15 @@ static void rave_sp_receive_frame(struct rave_sp *sp, const size_t payload_length = length - checksum_length; const u8 *crc_reported = &data[payload_length]; struct device *dev = &sp->serdev->dev; - u8 crc_calculated[checksum_length]; + u8 crc_calculated[RAVE_SP_CHECKSUM_SIZE]; + + if (unlikely(checksum_length > sizeof(crc_calculated))) { + dev_warn(dev, "Checksum too long, dropping\n"); + return; + } - print_hex_dump(KERN_DEBUG, "rave-sp rx: ", DUMP_PREFIX_NONE, - 16, 1, data, length, false); + print_hex_dump_debug("rave-sp rx: ", DUMP_PREFIX_NONE, + 16, 1, data, length, false); if (unlikely(length <= checksum_length)) { dev_warn(dev, "Dropping short frame\n"); @@ -512,8 +553,6 @@ static int rave_sp_receive_buf(struct serdev_device *serdev, /* FALLTHROUGH */ case RAVE_SP_EXPECT_ESCAPED_DATA: - deframer->data[deframer->length++] = byte; - if (deframer->length == sizeof(deframer->data)) { dev_warn(dev, "Bad frame: Too long\n"); /* @@ -528,6 +567,8 @@ static int rave_sp_receive_buf(struct serdev_device *serdev, goto reset_framer; } + deframer->data[deframer->length++] = byte; + /* * We've extracted out special byte, now we * can go back to regular data collecting @@ -609,6 +650,52 @@ static int rave_sp_default_cmd_translate(enum rave_sp_command command) } } +static const char *devm_rave_sp_version(struct device *dev, + struct rave_sp_version *version) +{ + /* + * NOTE: The format string below uses %02d to display u16 + * intentionally for the sake of backwards compatibility with + * legacy software. + */ + return devm_kasprintf(dev, GFP_KERNEL, "%02d%02d%02d.%c%c\n", + version->hardware, + le16_to_cpu(version->major), + version->minor, + version->letter[0], + version->letter[1]); +} + +static int rave_sp_get_status(struct rave_sp *sp) +{ + struct device *dev = &sp->serdev->dev; + u8 cmd[] = { + [0] = RAVE_SP_CMD_STATUS, + [1] = 0 + }; + struct rave_sp_status status; + const char *version; + int ret; + + ret = rave_sp_exec(sp, cmd, sizeof(cmd), &status, sizeof(status)); + if (ret) + return ret; + + version = devm_rave_sp_version(dev, &status.firmware_version); + if (!version) + return -ENOMEM; + + sp->part_number_firmware = version; + + version = devm_rave_sp_version(dev, &status.bootloader_version); + if (!version) + return -ENOMEM; + + sp->part_number_bootloader = version; + + return 0; +} + static const struct rave_sp_checksum rave_sp_checksum_8b2c = { .length = 1, .subroutine = csum_8b2c, @@ -657,6 +744,7 @@ static const struct serdev_device_ops rave_sp_serdev_device_ops = { static int rave_sp_probe(struct serdev_device *serdev) { struct device *dev = &serdev->dev; + const char *unknown = "unknown\n"; struct rave_sp *sp; u32 baud; int ret; @@ -689,6 +777,20 @@ static int rave_sp_probe(struct serdev_device *serdev) serdev_device_set_baudrate(serdev, baud); + ret = rave_sp_get_status(sp); + if (ret) { + dev_warn(dev, "Failed to get firmware status: %d\n", ret); + sp->part_number_firmware = unknown; + sp->part_number_bootloader = unknown; + } + + /* + * Those strings already have a \n embedded, so there's no + * need to have one in format string. + */ + dev_info(dev, "Firmware version: %s", sp->part_number_firmware); + dev_info(dev, "Bootloader version: %s", sp->part_number_bootloader); + return devm_of_platform_populate(dev); } diff --git a/drivers/mfd/rc5t583.c b/drivers/mfd/rc5t583.c index d12243d5ecb8..fd46de02b715 100644 --- a/drivers/mfd/rc5t583.c +++ b/drivers/mfd/rc5t583.c @@ -258,11 +258,9 @@ static int rc5t583_i2c_probe(struct i2c_client *i2c, return -EINVAL; } - rc5t583 = devm_kzalloc(&i2c->dev, sizeof(struct rc5t583), GFP_KERNEL); - if (!rc5t583) { - dev_err(&i2c->dev, "Memory allocation failed\n"); + rc5t583 = devm_kzalloc(&i2c->dev, sizeof(*rc5t583), GFP_KERNEL); + if (!rc5t583) return -ENOMEM; - } rc5t583->dev = &i2c->dev; i2c_set_clientdata(i2c, rc5t583); diff --git a/drivers/mfd/si476x-i2c.c b/drivers/mfd/si476x-i2c.c index e6a3d999a376..2c5ec93333c3 100644 --- a/drivers/mfd/si476x-i2c.c +++ b/drivers/mfd/si476x-i2c.c @@ -697,11 +697,9 @@ static int si476x_core_probe(struct i2c_client *client, int cell_num; core = devm_kzalloc(&client->dev, sizeof(*core), GFP_KERNEL); - if (!core) { - dev_err(&client->dev, - "failed to allocate 'struct si476x_core'\n"); + if (!core) return -ENOMEM; - } + core->client = client; core->regmap = devm_regmap_init_si476x(core); diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index ad774161a22d..2a87b0d2f21f 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c @@ -19,7 +19,7 @@ #include <linux/device.h> #include <linux/platform_device.h> #include <linux/pci.h> -#include <linux/i2c-gpio.h> +#include <linux/platform_data/i2c-gpio.h> #include <linux/gpio/machine.h> #include <linux/slab.h> @@ -1050,13 +1050,13 @@ static int sm501_register_gpio(struct sm501_devdata *sm) spin_lock_init(&gpio->lock); gpio->regs_res = request_mem_region(iobase, 0x20, "sm501-gpio"); - if (gpio->regs_res == NULL) { + if (!gpio->regs_res) { dev_err(sm->dev, "gpio: failed to request region\n"); return -ENXIO; } gpio->regs = ioremap(iobase, 0x20); - if (gpio->regs == NULL) { + if (!gpio->regs) { dev_err(sm->dev, "gpio: failed to remap registers\n"); ret = -ENXIO; goto err_claimed; @@ -1358,7 +1358,7 @@ static int sm501_init_dev(struct sm501_devdata *sm) sm501_register_gpio(sm); } - if (pdata && pdata->gpio_i2c != NULL && pdata->gpio_i2c_nr > 0) { + if (pdata && pdata->gpio_i2c && pdata->gpio_i2c_nr > 0) { if (!sm501_gpio_isregistered(sm)) dev_err(sm->dev, "no gpio available for i2c gpio.\n"); else @@ -1383,9 +1383,8 @@ static int sm501_plat_probe(struct platform_device *dev) struct sm501_devdata *sm; int ret; - sm = kzalloc(sizeof(struct sm501_devdata), GFP_KERNEL); - if (sm == NULL) { - dev_err(&dev->dev, "no memory for device data\n"); + sm = kzalloc(sizeof(*sm), GFP_KERNEL); + if (!sm) { ret = -ENOMEM; goto err1; } @@ -1403,8 +1402,7 @@ static int sm501_plat_probe(struct platform_device *dev) sm->io_res = platform_get_resource(dev, IORESOURCE_MEM, 1); sm->mem_res = platform_get_resource(dev, IORESOURCE_MEM, 0); - - if (sm->io_res == NULL || sm->mem_res == NULL) { + if (!sm->io_res || !sm->mem_res) { dev_err(&dev->dev, "failed to get IO resource\n"); ret = -ENOENT; goto err_res; @@ -1412,8 +1410,7 @@ static int sm501_plat_probe(struct platform_device *dev) sm->regs_claim = request_mem_region(sm->io_res->start, 0x100, "sm501"); - - if (sm->regs_claim == NULL) { + if (!sm->regs_claim) { dev_err(&dev->dev, "cannot claim registers\n"); ret = -EBUSY; goto err_res; @@ -1422,8 +1419,7 @@ static int sm501_plat_probe(struct platform_device *dev) platform_set_drvdata(dev, sm); sm->regs = ioremap(sm->io_res->start, resource_size(sm->io_res)); - - if (sm->regs == NULL) { + if (!sm->regs) { dev_err(&dev->dev, "cannot remap registers\n"); ret = -EIO; goto err_claim; @@ -1449,7 +1445,7 @@ static void sm501_set_power(struct sm501_devdata *sm, int on) { struct sm501_platdata *pd = sm->platdata; - if (pd == NULL) + if (!pd) return; if (pd->get_power) { @@ -1573,9 +1569,8 @@ static int sm501_pci_probe(struct pci_dev *dev, struct sm501_devdata *sm; int err; - sm = kzalloc(sizeof(struct sm501_devdata), GFP_KERNEL); - if (sm == NULL) { - dev_err(&dev->dev, "no memory for device data\n"); + sm = kzalloc(sizeof(*sm), GFP_KERNEL); + if (!sm) { err = -ENOMEM; goto err1; } @@ -1626,15 +1621,14 @@ static int sm501_pci_probe(struct pci_dev *dev, sm->regs_claim = request_mem_region(sm->io_res->start, 0x100, "sm501"); - if (sm->regs_claim == NULL) { + if (!sm->regs_claim) { dev_err(&dev->dev, "cannot claim registers\n"); err= -EBUSY; goto err3; } sm->regs = pci_ioremap_bar(dev, 1); - - if (sm->regs == NULL) { + if (!sm->regs) { dev_err(&dev->dev, "cannot remap registers\n"); err = -EIO; goto err4; diff --git a/drivers/mfd/smsc-ece1099.c b/drivers/mfd/smsc-ece1099.c index 93a8297de52a..57b792eb58fd 100644 --- a/drivers/mfd/smsc-ece1099.c +++ b/drivers/mfd/smsc-ece1099.c @@ -37,12 +37,9 @@ static int smsc_i2c_probe(struct i2c_client *i2c, int devid, rev, venid_l, venid_h; int ret; - smsc = devm_kzalloc(&i2c->dev, sizeof(struct smsc), - GFP_KERNEL); - if (!smsc) { - dev_err(&i2c->dev, "smsc mfd driver memory allocation failed\n"); + smsc = devm_kzalloc(&i2c->dev, sizeof(*smsc), GFP_KERNEL); + if (!smsc) return -ENOMEM; - } smsc->regmap = devm_regmap_init_i2c(i2c, &smsc_regmap_config); if (IS_ERR(smsc->regmap)) diff --git a/drivers/mfd/sprd-sc27xx-spi.c b/drivers/mfd/sprd-sc27xx-spi.c index 56a4782f0569..69df27769c21 100644 --- a/drivers/mfd/sprd-sc27xx-spi.c +++ b/drivers/mfd/sprd-sc27xx-spi.c @@ -111,6 +111,9 @@ static const struct mfd_cell sprd_pmic_devs[] = { }, { .name = "sc27xx-poweroff", .of_compatible = "sprd,sc27xx-poweroff", + }, { + .name = "sc27xx-syscon", + .of_compatible = "sprd,sc27xx-syscon", }, }; @@ -196,8 +199,9 @@ static int sprd_pmic_probe(struct spi_device *spi) ddata->irq_chip.num_irqs = pdata->num_irqs; ddata->irq_chip.mask_invert = true; - ddata->irqs = devm_kzalloc(&spi->dev, sizeof(struct regmap_irq) * - pdata->num_irqs, GFP_KERNEL); + ddata->irqs = devm_kcalloc(&spi->dev, + pdata->num_irqs, sizeof(struct regmap_irq), + GFP_KERNEL); if (!ddata->irqs) return -ENOMEM; diff --git a/drivers/mfd/stm32-timers.c b/drivers/mfd/stm32-timers.c index 1d347e5dfa79..efcd4b980c94 100644 --- a/drivers/mfd/stm32-timers.c +++ b/drivers/mfd/stm32-timers.c @@ -4,16 +4,156 @@ * Author: Benjamin Gaignard <benjamin.gaignard@st.com> */ +#include <linux/bitfield.h> #include <linux/mfd/stm32-timers.h> #include <linux/module.h> #include <linux/of_platform.h> #include <linux/reset.h> +#define STM32_TIMERS_MAX_REGISTERS 0x3fc + +/* DIER register DMA enable bits */ +static const u32 stm32_timers_dier_dmaen[STM32_TIMERS_MAX_DMAS] = { + TIM_DIER_CC1DE, + TIM_DIER_CC2DE, + TIM_DIER_CC3DE, + TIM_DIER_CC4DE, + TIM_DIER_UIE, + TIM_DIER_TDE, + TIM_DIER_COMDE +}; + +static void stm32_timers_dma_done(void *p) +{ + struct stm32_timers_dma *dma = p; + struct dma_tx_state state; + enum dma_status status; + + status = dmaengine_tx_status(dma->chan, dma->chan->cookie, &state); + if (status == DMA_COMPLETE) + complete(&dma->completion); +} + +/** + * stm32_timers_dma_burst_read - Read from timers registers using DMA. + * + * Read from STM32 timers registers using DMA on a single event. + * @dev: reference to stm32_timers MFD device + * @buf: DMA'able destination buffer + * @id: stm32_timers_dmas event identifier (ch[1..4], up, trig or com) + * @reg: registers start offset for DMA to read from (like CCRx for capture) + * @num_reg: number of registers to read upon each DMA request, starting @reg. + * @bursts: number of bursts to read (e.g. like two for pwm period capture) + * @tmo_ms: timeout (milliseconds) + */ +int stm32_timers_dma_burst_read(struct device *dev, u32 *buf, + enum stm32_timers_dmas id, u32 reg, + unsigned int num_reg, unsigned int bursts, + unsigned long tmo_ms) +{ + struct stm32_timers *ddata = dev_get_drvdata(dev); + unsigned long timeout = msecs_to_jiffies(tmo_ms); + struct regmap *regmap = ddata->regmap; + struct stm32_timers_dma *dma = &ddata->dma; + size_t len = num_reg * bursts * sizeof(u32); + struct dma_async_tx_descriptor *desc; + struct dma_slave_config config; + dma_cookie_t cookie; + dma_addr_t dma_buf; + u32 dbl, dba; + long err; + int ret; + + /* Sanity check */ + if (id < STM32_TIMERS_DMA_CH1 || id >= STM32_TIMERS_MAX_DMAS) + return -EINVAL; + + if (!num_reg || !bursts || reg > STM32_TIMERS_MAX_REGISTERS || + (reg + num_reg * sizeof(u32)) > STM32_TIMERS_MAX_REGISTERS) + return -EINVAL; + + if (!dma->chans[id]) + return -ENODEV; + mutex_lock(&dma->lock); + + /* Select DMA channel in use */ + dma->chan = dma->chans[id]; + dma_buf = dma_map_single(dev, buf, len, DMA_FROM_DEVICE); + if (dma_mapping_error(dev, dma_buf)) { + ret = -ENOMEM; + goto unlock; + } + + /* Prepare DMA read from timer registers, using DMA burst mode */ + memset(&config, 0, sizeof(config)); + config.src_addr = (dma_addr_t)dma->phys_base + TIM_DMAR; + config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + ret = dmaengine_slave_config(dma->chan, &config); + if (ret) + goto unmap; + + desc = dmaengine_prep_slave_single(dma->chan, dma_buf, len, + DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT); + if (!desc) { + ret = -EBUSY; + goto unmap; + } + + desc->callback = stm32_timers_dma_done; + desc->callback_param = dma; + cookie = dmaengine_submit(desc); + ret = dma_submit_error(cookie); + if (ret) + goto dma_term; + + reinit_completion(&dma->completion); + dma_async_issue_pending(dma->chan); + + /* Setup and enable timer DMA burst mode */ + dbl = FIELD_PREP(TIM_DCR_DBL, bursts - 1); + dba = FIELD_PREP(TIM_DCR_DBA, reg >> 2); + ret = regmap_write(regmap, TIM_DCR, dbl | dba); + if (ret) + goto dma_term; + + /* Clear pending flags before enabling DMA request */ + ret = regmap_write(regmap, TIM_SR, 0); + if (ret) + goto dcr_clr; + + ret = regmap_update_bits(regmap, TIM_DIER, stm32_timers_dier_dmaen[id], + stm32_timers_dier_dmaen[id]); + if (ret) + goto dcr_clr; + + err = wait_for_completion_interruptible_timeout(&dma->completion, + timeout); + if (err == 0) + ret = -ETIMEDOUT; + else if (err < 0) + ret = err; + + regmap_update_bits(regmap, TIM_DIER, stm32_timers_dier_dmaen[id], 0); + regmap_write(regmap, TIM_SR, 0); +dcr_clr: + regmap_write(regmap, TIM_DCR, 0); +dma_term: + dmaengine_terminate_all(dma->chan); +unmap: + dma_unmap_single(dev, dma_buf, len, DMA_FROM_DEVICE); +unlock: + dma->chan = NULL; + mutex_unlock(&dma->lock); + + return ret; +} +EXPORT_SYMBOL_GPL(stm32_timers_dma_burst_read); + static const struct regmap_config stm32_timers_regmap_cfg = { .reg_bits = 32, .val_bits = 32, .reg_stride = sizeof(u32), - .max_register = 0x3fc, + .max_register = STM32_TIMERS_MAX_REGISTERS, }; static void stm32_timers_get_arr_size(struct stm32_timers *ddata) @@ -27,12 +167,45 @@ static void stm32_timers_get_arr_size(struct stm32_timers *ddata) regmap_write(ddata->regmap, TIM_ARR, 0x0); } +static void stm32_timers_dma_probe(struct device *dev, + struct stm32_timers *ddata) +{ + int i; + char name[4]; + + init_completion(&ddata->dma.completion); + mutex_init(&ddata->dma.lock); + + /* Optional DMA support: get valid DMA channel(s) or NULL */ + for (i = STM32_TIMERS_DMA_CH1; i <= STM32_TIMERS_DMA_CH4; i++) { + snprintf(name, ARRAY_SIZE(name), "ch%1d", i + 1); + ddata->dma.chans[i] = dma_request_slave_channel(dev, name); + } + ddata->dma.chans[STM32_TIMERS_DMA_UP] = + dma_request_slave_channel(dev, "up"); + ddata->dma.chans[STM32_TIMERS_DMA_TRIG] = + dma_request_slave_channel(dev, "trig"); + ddata->dma.chans[STM32_TIMERS_DMA_COM] = + dma_request_slave_channel(dev, "com"); +} + +static void stm32_timers_dma_remove(struct device *dev, + struct stm32_timers *ddata) +{ + int i; + + for (i = STM32_TIMERS_DMA_CH1; i < STM32_TIMERS_MAX_DMAS; i++) + if (ddata->dma.chans[i]) + dma_release_channel(ddata->dma.chans[i]); +} + static int stm32_timers_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct stm32_timers *ddata; struct resource *res; void __iomem *mmio; + int ret; ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL); if (!ddata) @@ -43,6 +216,9 @@ static int stm32_timers_probe(struct platform_device *pdev) if (IS_ERR(mmio)) return PTR_ERR(mmio); + /* Timer physical addr for DMA */ + ddata->dma.phys_base = res->start; + ddata->regmap = devm_regmap_init_mmio_clk(dev, "int", mmio, &stm32_timers_regmap_cfg); if (IS_ERR(ddata->regmap)) @@ -54,9 +230,29 @@ static int stm32_timers_probe(struct platform_device *pdev) stm32_timers_get_arr_size(ddata); + stm32_timers_dma_probe(dev, ddata); + platform_set_drvdata(pdev, ddata); - return devm_of_platform_populate(&pdev->dev); + ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); + if (ret) + stm32_timers_dma_remove(dev, ddata); + + return ret; +} + +static int stm32_timers_remove(struct platform_device *pdev) +{ + struct stm32_timers *ddata = platform_get_drvdata(pdev); + + /* + * Don't use devm_ here: enfore of_platform_depopulate() happens before + * DMA are released, to avoid race on DMA. + */ + of_platform_depopulate(&pdev->dev); + stm32_timers_dma_remove(&pdev->dev, ddata); + + return 0; } static const struct of_device_id stm32_timers_of_match[] = { @@ -67,6 +263,7 @@ MODULE_DEVICE_TABLE(of, stm32_timers_of_match); static struct platform_driver stm32_timers_driver = { .probe = stm32_timers_probe, + .remove = stm32_timers_remove, .driver = { .name = "stm32-timers", .of_match_table = stm32_timers_of_match, diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c index 7eaa40bc703f..b6d05cd934e6 100644 --- a/drivers/mfd/syscon.c +++ b/drivers/mfd/syscon.c @@ -106,9 +106,11 @@ static struct syscon *of_syscon_register(struct device_node *np) } } + syscon_config.name = of_node_full_name(np); syscon_config.reg_stride = reg_io_width; syscon_config.val_bits = reg_io_width * 8; syscon_config.max_register = resource_size(&res) - reg_io_width; + syscon_config.name = of_node_full_name(np); regmap = regmap_init_mmio(NULL, base, &syscon_config); if (IS_ERR(regmap)) { diff --git a/drivers/mfd/ti_am335x_tscadc.c b/drivers/mfd/ti_am335x_tscadc.c index 3cd958a31f36..47012c0899cd 100644 --- a/drivers/mfd/ti_am335x_tscadc.c +++ b/drivers/mfd/ti_am335x_tscadc.c @@ -169,10 +169,9 @@ static int ti_tscadc_probe(struct platform_device *pdev) /* Allocate memory for device */ tscadc = devm_kzalloc(&pdev->dev, sizeof(*tscadc), GFP_KERNEL); - if (!tscadc) { - dev_err(&pdev->dev, "failed to allocate memory.\n"); + if (!tscadc) return -ENOMEM; - } + tscadc->dev = &pdev->dev; err = platform_get_irq(pdev, 0); diff --git a/drivers/mfd/timberdale.c b/drivers/mfd/timberdale.c index cd4a6d7d6750..436e34705af1 100644 --- a/drivers/mfd/timberdale.c +++ b/drivers/mfd/timberdale.c @@ -30,8 +30,8 @@ #include <linux/timb_gpio.h> #include <linux/i2c.h> -#include <linux/i2c-ocores.h> -#include <linux/i2c-xiic.h> +#include <linux/platform_data/i2c-ocores.h> +#include <linux/platform_data/i2c-xiic.h> #include <linux/spi/spi.h> #include <linux/spi/xilinx_spi.h> @@ -707,8 +707,8 @@ static int timb_probe(struct pci_dev *dev, goto err_config; } - msix_entries = kzalloc(TIMBERDALE_NR_IRQS * sizeof(*msix_entries), - GFP_KERNEL); + msix_entries = kcalloc(TIMBERDALE_NR_IRQS, sizeof(*msix_entries), + GFP_KERNEL); if (!msix_entries) goto err_config; @@ -777,7 +777,7 @@ static int timb_probe(struct pci_dev *dev, &dev->resource[0], msix_entries[0].vector, NULL); break; default: - dev_err(&dev->dev, "Uknown IP setup: %d.%d.%d\n", + dev_err(&dev->dev, "Unknown IP setup: %d.%d.%d\n", priv->fw.major, priv->fw.minor, ip_setup); err = -ENODEV; goto err_mfd; diff --git a/drivers/mfd/tps65090.c b/drivers/mfd/tps65090.c index d7ec318c40c3..f13e4cd06e89 100644 --- a/drivers/mfd/tps65090.c +++ b/drivers/mfd/tps65090.c @@ -192,10 +192,8 @@ static int tps65090_i2c_probe(struct i2c_client *client, irq_base = pdata->irq_base; tps65090 = devm_kzalloc(&client->dev, sizeof(*tps65090), GFP_KERNEL); - if (!tps65090) { - dev_err(&client->dev, "mem alloc for tps65090 failed\n"); + if (!tps65090) return -ENOMEM; - } tps65090->dev = &client->dev; i2c_set_clientdata(client, tps65090); diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index 5628a6b5b19b..b89379782741 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c @@ -423,10 +423,8 @@ static struct tps6586x_platform_data *tps6586x_parse_dt(struct i2c_client *clien struct tps6586x_platform_data *pdata; pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) { - dev_err(&client->dev, "Memory allocation failed\n"); + if (!pdata) return NULL; - } pdata->num_subdevs = 0; pdata->subdevs = NULL; diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index 8263605f6d2f..bf16cbe6fd88 100644 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -229,7 +229,7 @@ static struct regmap_irq_chip tps65910_irq_chip = { static int tps65910_irq_init(struct tps65910 *tps65910, int irq, struct tps65910_platform_data *pdata) { - int ret = 0; + int ret; static struct regmap_irq_chip *tps6591x_irqs_chip; if (!irq) { @@ -312,14 +312,14 @@ static int tps65910_ck32k_init(struct tps65910 *tps65910, static int tps65910_sleepinit(struct tps65910 *tps65910, struct tps65910_board *pmic_pdata) { - struct device *dev = NULL; - int ret = 0; - - dev = tps65910->dev; + struct device *dev; + int ret; if (!pmic_pdata->en_dev_slp) return 0; + dev = tps65910->dev; + /* enabling SLEEP device state */ ret = tps65910_reg_set_bits(tps65910, TPS65910_DEVCTRL, DEVCTRL_DEV_SLP_MASK); @@ -383,7 +383,7 @@ static struct tps65910_board *tps65910_parse_dt(struct i2c_client *client, struct tps65910_board *board_info; unsigned int prop; const struct of_device_id *match; - int ret = 0; + int ret; match = of_match_device(tps65910_of_match, &client->dev); if (!match) { @@ -395,10 +395,8 @@ static struct tps65910_board *tps65910_parse_dt(struct i2c_client *client, board_info = devm_kzalloc(&client->dev, sizeof(*board_info), GFP_KERNEL); - if (!board_info) { - dev_err(&client->dev, "Failed to allocate pdata\n"); + if (!board_info) return NULL; - } ret = of_property_read_u32(np, "ti,vmbch-threshold", &prop); if (!ret) @@ -462,7 +460,7 @@ static int tps65910_i2c_probe(struct i2c_client *i2c, struct tps65910_board *of_pmic_plat_data = NULL; struct tps65910_platform_data *init_data; unsigned long chip_id = id->driver_data; - int ret = 0; + int ret; pmic_plat_data = dev_get_platdata(&i2c->dev); diff --git a/drivers/mfd/tps65911-comparator.c b/drivers/mfd/tps65911-comparator.c index c0789f81a1c5..33591767fb9b 100644 --- a/drivers/mfd/tps65911-comparator.c +++ b/drivers/mfd/tps65911-comparator.c @@ -22,9 +22,8 @@ #include <linux/gpio.h> #include <linux/mfd/tps65910.h> -#define COMP 0 -#define COMP1 1 -#define COMP2 2 +#define COMP1 0 +#define COMP2 1 /* Comparator 1 voltage selection table in millivolts */ static const u16 COMP_VSEL_TABLE[] = { @@ -63,9 +62,6 @@ static int comp_threshold_set(struct tps65910 *tps65910, int id, int voltage) int ret; u8 index = 0, val; - if (id == COMP) - return 0; - while (curr_voltage < tps_comp.uV_max) { curr_voltage = tps_comp.vsel_table[index]; if (curr_voltage >= voltage) @@ -78,7 +74,7 @@ static int comp_threshold_set(struct tps65910 *tps65910, int id, int voltage) return -EINVAL; val = index << 1; - ret = tps65910->write(tps65910, tps_comp.reg, 1, &val); + ret = tps65910_reg_write(tps65910, tps_comp.reg, val); return ret; } @@ -86,13 +82,10 @@ static int comp_threshold_set(struct tps65910 *tps65910, int id, int voltage) static int comp_threshold_get(struct tps65910 *tps65910, int id) { struct comparator tps_comp = tps_comparators[id]; + unsigned int val; int ret; - u8 val; - - if (id == COMP) - return 0; - ret = tps65910->read(tps65910, tps_comp.reg, 1, &val); + ret = tps65910_reg_read(tps65910, tps_comp.reg, &val); if (ret < 0) return ret; diff --git a/drivers/mfd/tps68470.c b/drivers/mfd/tps68470.c index 189efaea054c..a5981a79b29a 100644 --- a/drivers/mfd/tps68470.c +++ b/drivers/mfd/tps68470.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * TPS68470 chip Parent driver * @@ -8,15 +9,6 @@ * Tianshu Qiu <tian.shu.qiu@intel.com> * Jian Xu Zheng <jian.xu.zheng@intel.com> * Yuning Pu <yuning.pu@intel.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/acpi.h> diff --git a/drivers/mfd/tps80031.c b/drivers/mfd/tps80031.c index 0812df3b0d47..608c7f77830e 100644 --- a/drivers/mfd/tps80031.c +++ b/drivers/mfd/tps80031.c @@ -431,10 +431,8 @@ static int tps80031_probe(struct i2c_client *client, } tps80031 = devm_kzalloc(&client->dev, sizeof(*tps80031), GFP_KERNEL); - if (!tps80031) { - dev_err(&client->dev, "Malloc failed for tps80031\n"); + if (!tps80031) return -ENOMEM; - } for (i = 0; i < TPS80031_NUM_SLAVES; i++) { if (tps80031_slave_address[i] == client->addr) diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index d3133a371e27..4be3d239da9e 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -1139,8 +1139,9 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) } num_slaves = twl_get_num_slaves(); - twl_priv->twl_modules = devm_kzalloc(&client->dev, - sizeof(struct twl_client) * num_slaves, + twl_priv->twl_modules = devm_kcalloc(&client->dev, + num_slaves, + sizeof(struct twl_client), GFP_KERNEL); if (!twl_priv->twl_modules) { status = -ENOMEM; @@ -1177,7 +1178,7 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) twl_priv->ready = true; /* setup clock framework */ - clocks_init(&pdev->dev, pdata ? pdata->clock : NULL); + clocks_init(&client->dev, pdata ? pdata->clock : NULL); /* read TWL IDCODE Register */ if (twl_class_is_4030()) { diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c index e3ec8dfa9f1e..e939431ed10c 100644 --- a/drivers/mfd/twl6030-irq.c +++ b/drivers/mfd/twl6030-irq.c @@ -392,10 +392,8 @@ int twl6030_init_irq(struct device *dev, int irq_num) nr_irqs = TWL6030_NR_IRQS; twl6030_irq = devm_kzalloc(dev, sizeof(*twl6030_irq), GFP_KERNEL); - if (!twl6030_irq) { - dev_err(dev, "twl6030_irq: Memory allocation failed\n"); + if (!twl6030_irq) return -ENOMEM; - } mask[0] = 0xFF; mask[1] = 0xFF; diff --git a/drivers/mfd/viperboard.c b/drivers/mfd/viperboard.c index e6b3c70aeb22..e9f61262d583 100644 --- a/drivers/mfd/viperboard.c +++ b/drivers/mfd/viperboard.c @@ -59,10 +59,8 @@ static int vprbrd_probe(struct usb_interface *interface, /* allocate memory for our device state and initialize it */ vb = kzalloc(sizeof(*vb), GFP_KERNEL); - if (vb == NULL) { - dev_err(&interface->dev, "Out of memory\n"); + if (!vb) return -ENOMEM; - } mutex_init(&vb->lock); diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index 953d0790ffd5..5d5888ee2966 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -368,9 +368,10 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq) goto err; } - wm8994->supplies = devm_kzalloc(wm8994->dev, - sizeof(struct regulator_bulk_data) * - wm8994->num_supplies, GFP_KERNEL); + wm8994->supplies = devm_kcalloc(wm8994->dev, + wm8994->num_supplies, + sizeof(struct regulator_bulk_data), + GFP_KERNEL); if (!wm8994->supplies) { ret = -ENOMEM; goto err; diff --git a/drivers/mfd/wm97xx-core.c b/drivers/mfd/wm97xx-core.c index 4141ee52a70b..f5a8347f837f 100644 --- a/drivers/mfd/wm97xx-core.c +++ b/drivers/mfd/wm97xx-core.c @@ -278,7 +278,7 @@ static int wm97xx_ac97_probe(struct ac97_codec_device *adev) codec_pdata = &wm97xx->codec_pdata; codec_pdata->ac97 = wm97xx->ac97; - codec_pdata->batt_pdata = pdata->batt_pdata; + codec_pdata->batt_pdata = pdata ? pdata->batt_pdata : NULL; switch (adev->vendor_id) { case WM9705_VENDOR_ID: diff --git a/drivers/misc/altera-stapl/altera.c b/drivers/misc/altera-stapl/altera.c index f53e217e963f..ef83a9078646 100644 --- a/drivers/misc/altera-stapl/altera.c +++ b/drivers/misc/altera-stapl/altera.c @@ -304,13 +304,13 @@ static int altera_execute(struct altera_state *astate, if (sym_count <= 0) goto exit_done; - vars = kzalloc(sym_count * sizeof(long), GFP_KERNEL); + vars = kcalloc(sym_count, sizeof(long), GFP_KERNEL); if (vars == NULL) status = -ENOMEM; if (status == 0) { - var_size = kzalloc(sym_count * sizeof(s32), GFP_KERNEL); + var_size = kcalloc(sym_count, sizeof(s32), GFP_KERNEL); if (var_size == NULL) status = -ENOMEM; @@ -1136,7 +1136,7 @@ exit_done: /* Allocate a writable buffer for this array */ count = var_size[variable_id]; long_tmp = vars[variable_id]; - longptr_tmp = kzalloc(count * sizeof(long), + longptr_tmp = kcalloc(count, sizeof(long), GFP_KERNEL); vars[variable_id] = (long)longptr_tmp; diff --git a/drivers/misc/cxl/guest.c b/drivers/misc/cxl/guest.c index f58b4b6c79f2..4644f16606a3 100644 --- a/drivers/misc/cxl/guest.c +++ b/drivers/misc/cxl/guest.c @@ -89,7 +89,7 @@ static ssize_t guest_collect_vpd(struct cxl *adapter, struct cxl_afu *afu, mod = 0; } - vpd_buf = kzalloc(entries * sizeof(unsigned long *), GFP_KERNEL); + vpd_buf = kcalloc(entries, sizeof(unsigned long *), GFP_KERNEL); if (!vpd_buf) return -ENOMEM; diff --git a/drivers/misc/cxl/of.c b/drivers/misc/cxl/of.c index ec175ea5dfba..aff181cd0bf2 100644 --- a/drivers/misc/cxl/of.c +++ b/drivers/misc/cxl/of.c @@ -302,7 +302,7 @@ static int read_adapter_irq_config(struct cxl *adapter, struct device_node *np) if (nranges == 0 || (nranges * 2 * sizeof(int)) != len) return -EINVAL; - adapter->guest->irq_avail = kzalloc(nranges * sizeof(struct irq_avail), + adapter->guest->irq_avail = kcalloc(nranges, sizeof(struct irq_avail), GFP_KERNEL); if (adapter->guest->irq_avail == NULL) return -ENOMEM; diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index 33053b0d1fdf..f5cc517d1131 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -532,6 +532,45 @@ static int at24_get_pdata(struct device *dev, struct at24_platform_data *pdata) return 0; } +static void at24_remove_dummy_clients(struct at24_data *at24) +{ + int i; + + for (i = 1; i < at24->num_addresses; i++) + i2c_unregister_device(at24->client[i].client); +} + +static int at24_make_dummy_client(struct at24_data *at24, unsigned int index, + struct regmap_config *regmap_config) +{ + struct i2c_client *base_client, *dummy_client; + unsigned short int addr; + struct regmap *regmap; + struct device *dev; + + base_client = at24->client[0].client; + dev = &base_client->dev; + addr = base_client->addr + index; + + dummy_client = i2c_new_dummy(base_client->adapter, + base_client->addr + index); + if (!dummy_client) { + dev_err(dev, "address 0x%02x unavailable\n", addr); + return -EADDRINUSE; + } + + regmap = devm_regmap_init_i2c(dummy_client, regmap_config); + if (IS_ERR(regmap)) { + i2c_unregister_device(dummy_client); + return PTR_ERR(regmap); + } + + at24->client[index].client = dummy_client; + at24->client[index].regmap = regmap; + + return 0; +} + static unsigned int at24_get_offset_adj(u8 flags, unsigned int byte_len) { if (flags & AT24_FLAG_MAC) { @@ -637,20 +676,10 @@ static int at24_probe(struct i2c_client *client) /* use dummy devices for multiple-address chips */ for (i = 1; i < num_addresses; i++) { - at24->client[i].client = i2c_new_dummy(client->adapter, - client->addr + i); - if (!at24->client[i].client) { - dev_err(dev, "address 0x%02x unavailable\n", - client->addr + i); - err = -EADDRINUSE; - goto err_clients; - } - at24->client[i].regmap = devm_regmap_init_i2c( - at24->client[i].client, - ®map_config); - if (IS_ERR(at24->client[i].regmap)) { - err = PTR_ERR(at24->client[i].regmap); - goto err_clients; + err = at24_make_dummy_client(at24, i, ®map_config); + if (err) { + at24_remove_dummy_clients(at24); + return err; } } @@ -685,7 +714,7 @@ static int at24_probe(struct i2c_client *client) nvmem_config.word_size = 1; nvmem_config.size = pdata.byte_len; - at24->nvmem = nvmem_register(&nvmem_config); + at24->nvmem = devm_nvmem_register(dev, &nvmem_config); if (IS_ERR(at24->nvmem)) { err = PTR_ERR(at24->nvmem); goto err_clients; @@ -702,10 +731,7 @@ static int at24_probe(struct i2c_client *client) return 0; err_clients: - for (i = 1; i < num_addresses; i++) - if (at24->client[i].client) - i2c_unregister_device(at24->client[i].client); - + at24_remove_dummy_clients(at24); pm_runtime_disable(dev); return err; @@ -714,15 +740,10 @@ err_clients: static int at24_remove(struct i2c_client *client) { struct at24_data *at24; - int i; at24 = i2c_get_clientdata(client); - nvmem_unregister(at24->nvmem); - - for (i = 1; i < at24->num_addresses; i++) - i2c_unregister_device(at24->client[i].client); - + at24_remove_dummy_clients(at24); pm_runtime_disable(&client->dev); pm_runtime_set_suspended(&client->dev); diff --git a/drivers/misc/eeprom/idt_89hpesx.c b/drivers/misc/eeprom/idt_89hpesx.c index 34a5a41578d7..59dc24bb70ec 100644 --- a/drivers/misc/eeprom/idt_89hpesx.c +++ b/drivers/misc/eeprom/idt_89hpesx.c @@ -964,7 +964,7 @@ static ssize_t idt_dbgfs_csr_write(struct file *filep, const char __user *ubuf, if (colon_ch != NULL) { csraddr_len = colon_ch - buf; csraddr_str = - kmalloc(sizeof(char)*(csraddr_len + 1), GFP_KERNEL); + kmalloc(csraddr_len + 1, GFP_KERNEL); if (csraddr_str == NULL) { ret = -ENOMEM; goto free_buf; diff --git a/drivers/misc/genwqe/card_ddcb.c b/drivers/misc/genwqe/card_ddcb.c index b7f8d35c17a9..656449cb4476 100644 --- a/drivers/misc/genwqe/card_ddcb.c +++ b/drivers/misc/genwqe/card_ddcb.c @@ -1048,15 +1048,16 @@ static int setup_ddcb_queue(struct genwqe_dev *cd, struct ddcb_queue *queue) "[%s] **err: could not allocate DDCB **\n", __func__); return -ENOMEM; } - queue->ddcb_req = kzalloc(sizeof(struct ddcb_requ *) * - queue->ddcb_max, GFP_KERNEL); + queue->ddcb_req = kcalloc(queue->ddcb_max, sizeof(struct ddcb_requ *), + GFP_KERNEL); if (!queue->ddcb_req) { rc = -ENOMEM; goto free_ddcbs; } - queue->ddcb_waitqs = kzalloc(sizeof(wait_queue_head_t) * - queue->ddcb_max, GFP_KERNEL); + queue->ddcb_waitqs = kcalloc(queue->ddcb_max, + sizeof(wait_queue_head_t), + GFP_KERNEL); if (!queue->ddcb_waitqs) { rc = -ENOMEM; goto free_requs; diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c index 0c775d6fcf59..83fc748a91a7 100644 --- a/drivers/misc/sgi-xp/xpc_main.c +++ b/drivers/misc/sgi-xp/xpc_main.c @@ -416,7 +416,8 @@ xpc_setup_ch_structures(struct xpc_partition *part) * memory. */ DBUG_ON(part->channels != NULL); - part->channels = kzalloc(sizeof(struct xpc_channel) * XPC_MAX_NCHANNELS, + part->channels = kcalloc(XPC_MAX_NCHANNELS, + sizeof(struct xpc_channel), GFP_KERNEL); if (part->channels == NULL) { dev_err(xpc_chan, "can't get memory for channels\n"); @@ -905,8 +906,9 @@ xpc_setup_partitions(void) short partid; struct xpc_partition *part; - xpc_partitions = kzalloc(sizeof(struct xpc_partition) * - xp_max_npartitions, GFP_KERNEL); + xpc_partitions = kcalloc(xp_max_npartitions, + sizeof(struct xpc_partition), + GFP_KERNEL); if (xpc_partitions == NULL) { dev_err(xpc_part, "can't get memory for partition structure\n"); return -ENOMEM; diff --git a/drivers/misc/sgi-xp/xpc_partition.c b/drivers/misc/sgi-xp/xpc_partition.c index 6956f7e7d439..7284413dabfd 100644 --- a/drivers/misc/sgi-xp/xpc_partition.c +++ b/drivers/misc/sgi-xp/xpc_partition.c @@ -425,7 +425,7 @@ xpc_discovery(void) if (remote_rp == NULL) return; - discovered_nasids = kzalloc(sizeof(long) * xpc_nasid_mask_nlongs, + discovered_nasids = kcalloc(xpc_nasid_mask_nlongs, sizeof(long), GFP_KERNEL); if (discovered_nasids == NULL) { kfree(remote_rp_base); diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c index 216d5c756236..44d750d98bc8 100644 --- a/drivers/misc/sgi-xp/xpnet.c +++ b/drivers/misc/sgi-xp/xpnet.c @@ -520,8 +520,9 @@ xpnet_init(void) dev_info(xpnet, "registering network device %s\n", XPNET_DEVICE_NAME); - xpnet_broadcast_partitions = kzalloc(BITS_TO_LONGS(xp_max_npartitions) * - sizeof(long), GFP_KERNEL); + xpnet_broadcast_partitions = kcalloc(BITS_TO_LONGS(xp_max_npartitions), + sizeof(long), + GFP_KERNEL); if (xpnet_broadcast_partitions == NULL) return -ENOMEM; diff --git a/drivers/misc/sram.c b/drivers/misc/sram.c index fc0415771c00..c5dc6095686a 100644 --- a/drivers/misc/sram.c +++ b/drivers/misc/sram.c @@ -185,7 +185,7 @@ static int sram_reserve_regions(struct sram_dev *sram, struct resource *res) * after the reserved blocks from the dt are processed. */ nblocks = (np) ? of_get_available_child_count(np) + 1 : 1; - rblocks = kzalloc((nblocks) * sizeof(*rblocks), GFP_KERNEL); + rblocks = kcalloc(nblocks, sizeof(*rblocks), GFP_KERNEL); if (!rblocks) return -ENOMEM; @@ -264,8 +264,8 @@ static int sram_reserve_regions(struct sram_dev *sram, struct resource *res) list_sort(NULL, &reserve_list, sram_reserve_cmp); if (exports) { - sram->partition = devm_kzalloc(sram->dev, - exports * sizeof(*sram->partition), + sram->partition = devm_kcalloc(sram->dev, + exports, sizeof(*sram->partition), GFP_KERNEL); if (!sram->partition) { ret = -ENOMEM; diff --git a/drivers/misc/vmw_vmci/vmci_queue_pair.c b/drivers/misc/vmw_vmci/vmci_queue_pair.c index 0339538c182d..b4d7774cfe07 100644 --- a/drivers/misc/vmw_vmci/vmci_queue_pair.c +++ b/drivers/misc/vmw_vmci/vmci_queue_pair.c @@ -449,12 +449,14 @@ static int qp_alloc_ppn_set(void *prod_q, return VMCI_ERROR_ALREADY_EXISTS; produce_ppns = - kmalloc(num_produce_pages * sizeof(*produce_ppns), GFP_KERNEL); + kmalloc_array(num_produce_pages, sizeof(*produce_ppns), + GFP_KERNEL); if (!produce_ppns) return VMCI_ERROR_NO_MEM; consume_ppns = - kmalloc(num_consume_pages * sizeof(*consume_ppns), GFP_KERNEL); + kmalloc_array(num_consume_pages, sizeof(*consume_ppns), + GFP_KERNEL); if (!consume_ppns) { kfree(produce_ppns); return VMCI_ERROR_NO_MEM; diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c index f3a7c8ece4be..88347ce78f23 100644 --- a/drivers/mmc/host/sdhci-omap.c +++ b/drivers/mmc/host/sdhci-omap.c @@ -797,8 +797,10 @@ static int sdhci_omap_config_iodelay_pinctrl_state(struct sdhci_omap_host if (!(omap_host->flags & SDHCI_OMAP_REQUIRE_IODELAY)) return 0; - pinctrl_state = devm_kzalloc(dev, sizeof(*pinctrl_state) * - (MMC_TIMING_MMC_HS200 + 1), GFP_KERNEL); + pinctrl_state = devm_kcalloc(dev, + MMC_TIMING_MMC_HS200 + 1, + sizeof(*pinctrl_state), + GFP_KERNEL); if (!pinctrl_state) return -ENOMEM; diff --git a/drivers/mtd/ar7part.c b/drivers/mtd/ar7part.c index 90575deff0ae..fc15ec58230a 100644 --- a/drivers/mtd/ar7part.c +++ b/drivers/mtd/ar7part.c @@ -55,7 +55,7 @@ static int create_mtd_partitions(struct mtd_info *master, int retries = 10; struct mtd_partition *ar7_parts; - ar7_parts = kzalloc(sizeof(*ar7_parts) * AR7_PARTS, GFP_KERNEL); + ar7_parts = kcalloc(AR7_PARTS, sizeof(*ar7_parts), GFP_KERNEL); if (!ar7_parts) return -ENOMEM; ar7_parts[0].name = "loader"; diff --git a/drivers/mtd/bcm47xxpart.c b/drivers/mtd/bcm47xxpart.c index 0f93d2239352..fc424b185b08 100644 --- a/drivers/mtd/bcm47xxpart.c +++ b/drivers/mtd/bcm47xxpart.c @@ -110,7 +110,7 @@ static int bcm47xxpart_parse(struct mtd_info *master, blocksize = 0x1000; /* Alloc */ - parts = kzalloc(sizeof(struct mtd_partition) * BCM47XXPART_MAX_PARTS, + parts = kcalloc(BCM47XXPART_MAX_PARTS, sizeof(struct mtd_partition), GFP_KERNEL); if (!parts) return -ENOMEM; diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index f5695be14499..6e8e7b1bb34b 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -608,8 +608,9 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd) mtd->size = devsize * cfi->numchips; mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips; - mtd->eraseregions = kzalloc(sizeof(struct mtd_erase_region_info) - * mtd->numeraseregions, GFP_KERNEL); + mtd->eraseregions = kcalloc(mtd->numeraseregions, + sizeof(struct mtd_erase_region_info), + GFP_KERNEL); if (!mtd->eraseregions) goto setup_err; @@ -758,7 +759,9 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd, newcfi = kmalloc(sizeof(struct cfi_private) + numvirtchips * sizeof(struct flchip), GFP_KERNEL); if (!newcfi) return -ENOMEM; - shared = kmalloc(sizeof(struct flchip_shared) * cfi->numchips, GFP_KERNEL); + shared = kmalloc_array(cfi->numchips, + sizeof(struct flchip_shared), + GFP_KERNEL); if (!shared) { kfree(newcfi); return -ENOMEM; diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 7c889eca9ab0..a0c655628d6d 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -692,8 +692,9 @@ static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd) mtd->size = devsize * cfi->numchips; mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips; - mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) - * mtd->numeraseregions, GFP_KERNEL); + mtd->eraseregions = kmalloc_array(mtd->numeraseregions, + sizeof(struct mtd_erase_region_info), + GFP_KERNEL); if (!mtd->eraseregions) goto setup_err; @@ -2635,7 +2636,7 @@ static int __maybe_unused cfi_ppb_unlock(struct mtd_info *mtd, loff_t ofs, * first check the locking status of all sectors and save * it for future use. */ - sect = kzalloc(MAX_SECTORS * sizeof(struct ppb_lock), GFP_KERNEL); + sect = kcalloc(MAX_SECTORS, sizeof(struct ppb_lock), GFP_KERNEL); if (!sect) return -ENOMEM; diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c index 7b7658a05036..35aa72b720a6 100644 --- a/drivers/mtd/chips/cfi_cmdset_0020.c +++ b/drivers/mtd/chips/cfi_cmdset_0020.c @@ -184,8 +184,9 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map) mtd->size = devsize * cfi->numchips; mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips; - mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) - * mtd->numeraseregions, GFP_KERNEL); + mtd->eraseregions = kmalloc_array(mtd->numeraseregions, + sizeof(struct mtd_erase_region_info), + GFP_KERNEL); if (!mtd->eraseregions) { kfree(cfi->cmdset_priv); kfree(mtd); diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index 802d8f159e90..512bd4c2eec0 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c @@ -1827,7 +1827,7 @@ doc_probe_device(struct docg3_cascade *cascade, int floor, struct device *dev) mtd->dev.parent = dev; bbt_nbpages = DIV_ROUND_UP(docg3->max_block + 1, 8 * DOC_LAYOUT_PAGE_SIZE); - docg3->bbt = kzalloc(bbt_nbpages * DOC_LAYOUT_PAGE_SIZE, GFP_KERNEL); + docg3->bbt = kcalloc(DOC_LAYOUT_PAGE_SIZE, bbt_nbpages, GFP_KERNEL); if (!docg3->bbt) goto nomem3; @@ -1993,7 +1993,7 @@ static int __init docg3_probe(struct platform_device *pdev) base = devm_ioremap(dev, ress->start, DOC_IOSPACE_SIZE); ret = -ENOMEM; - cascade = devm_kzalloc(dev, sizeof(*cascade) * DOC_MAX_NBFLOORS, + cascade = devm_kcalloc(dev, DOC_MAX_NBFLOORS, sizeof(*cascade), GFP_KERNEL); if (!cascade) return ret; diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c index ef6ad2551d57..2578f27914ef 100644 --- a/drivers/mtd/ftl.c +++ b/drivers/mtd/ftl.c @@ -201,15 +201,16 @@ static int build_maps(partition_t *part) /* Set up erase unit maps */ part->DataUnits = le16_to_cpu(part->header.NumEraseUnits) - part->header.NumTransferUnits; - part->EUNInfo = kmalloc(part->DataUnits * sizeof(struct eun_info_t), - GFP_KERNEL); + part->EUNInfo = kmalloc_array(part->DataUnits, sizeof(struct eun_info_t), + GFP_KERNEL); if (!part->EUNInfo) goto out; for (i = 0; i < part->DataUnits; i++) part->EUNInfo[i].Offset = 0xffffffff; part->XferInfo = - kmalloc(part->header.NumTransferUnits * sizeof(struct xfer_info_t), - GFP_KERNEL); + kmalloc_array(part->header.NumTransferUnits, + sizeof(struct xfer_info_t), + GFP_KERNEL); if (!part->XferInfo) goto out_EUNInfo; @@ -262,15 +263,15 @@ static int build_maps(partition_t *part) /* Set up virtual page map */ blocks = le32_to_cpu(header.FormattedSize) >> header.BlockSize; - part->VirtualBlockMap = vmalloc(blocks * sizeof(uint32_t)); + part->VirtualBlockMap = vmalloc(array_size(blocks, sizeof(uint32_t))); if (!part->VirtualBlockMap) goto out_XferInfo; memset(part->VirtualBlockMap, 0xff, blocks * sizeof(uint32_t)); part->BlocksPerUnit = (1 << header.EraseUnitSize) >> header.BlockSize; - part->bam_cache = kmalloc(part->BlocksPerUnit * sizeof(uint32_t), - GFP_KERNEL); + part->bam_cache = kmalloc_array(part->BlocksPerUnit, sizeof(uint32_t), + GFP_KERNEL); if (!part->bam_cache) goto out_VirtualBlockMap; diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c index 2d598412972d..10d977e9709d 100644 --- a/drivers/mtd/inftlmount.c +++ b/drivers/mtd/inftlmount.c @@ -270,7 +270,8 @@ static int find_boot_record(struct INFTLrecord *inftl) inftl->nb_blocks = ip->lastUnit + 1; /* Memory alloc */ - inftl->PUtable = kmalloc(inftl->nb_blocks * sizeof(u16), GFP_KERNEL); + inftl->PUtable = kmalloc_array(inftl->nb_blocks, sizeof(u16), + GFP_KERNEL); if (!inftl->PUtable) { printk(KERN_WARNING "INFTL: allocation of PUtable " "failed (%zd bytes)\n", @@ -278,7 +279,8 @@ static int find_boot_record(struct INFTLrecord *inftl) return -ENOMEM; } - inftl->VUtable = kmalloc(inftl->nb_blocks * sizeof(u16), GFP_KERNEL); + inftl->VUtable = kmalloc_array(inftl->nb_blocks, sizeof(u16), + GFP_KERNEL); if (!inftl->VUtable) { kfree(inftl->PUtable); printk(KERN_WARNING "INFTL: allocation of VUtable " diff --git a/drivers/mtd/lpddr/lpddr_cmds.c b/drivers/mtd/lpddr/lpddr_cmds.c index 5c5ba3c7c79d..b13557fe52bd 100644 --- a/drivers/mtd/lpddr/lpddr_cmds.c +++ b/drivers/mtd/lpddr/lpddr_cmds.c @@ -78,7 +78,7 @@ struct mtd_info *lpddr_cmdset(struct map_info *map) mtd->erasesize = 1 << lpddr->qinfo->UniformBlockSizeShift; mtd->writesize = 1 << lpddr->qinfo->BufSizeShift; - shared = kmalloc(sizeof(struct flchip_shared) * lpddr->numchips, + shared = kmalloc_array(lpddr->numchips, sizeof(struct flchip_shared), GFP_KERNEL); if (!shared) { kfree(lpddr); diff --git a/drivers/mtd/maps/physmap_of_core.c b/drivers/mtd/maps/physmap_of_core.c index 527b1682381f..4129535b8e46 100644 --- a/drivers/mtd/maps/physmap_of_core.c +++ b/drivers/mtd/maps/physmap_of_core.c @@ -124,7 +124,7 @@ static const char * const *of_get_probes(struct device_node *dp) if (count < 0) return part_probe_types_def; - res = kzalloc((count + 1) * sizeof(*res), GFP_KERNEL); + res = kcalloc(count + 1, sizeof(*res), GFP_KERNEL); if (!res) return NULL; @@ -197,7 +197,7 @@ static int of_flash_probe(struct platform_device *dev) dev_set_drvdata(&dev->dev, info); - mtd_list = kzalloc(sizeof(*mtd_list) * count, GFP_KERNEL); + mtd_list = kcalloc(count, sizeof(*mtd_list), GFP_KERNEL); if (!mtd_list) goto err_flash_remove; diff --git a/drivers/mtd/maps/vmu-flash.c b/drivers/mtd/maps/vmu-flash.c index 6b223cfe92b7..c5d4b6589488 100644 --- a/drivers/mtd/maps/vmu-flash.c +++ b/drivers/mtd/maps/vmu-flash.c @@ -629,15 +629,15 @@ static int vmu_connect(struct maple_device *mdev) * Not sure there are actually any multi-partition devices in the * real world, but the hardware supports them, so, so will we */ - card->parts = kmalloc(sizeof(struct vmupart) * card->partitions, - GFP_KERNEL); + card->parts = kmalloc_array(card->partitions, sizeof(struct vmupart), + GFP_KERNEL); if (!card->parts) { error = -ENOMEM; goto fail_partitions; } - card->mtd = kmalloc(sizeof(struct mtd_info) * card->partitions, - GFP_KERNEL); + card->mtd = kmalloc_array(card->partitions, sizeof(struct mtd_info), + GFP_KERNEL); if (!card->mtd) { error = -ENOMEM; goto fail_mtd_info; diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index 6b86d1a73cf2..cbc5925e6440 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c @@ -778,8 +778,9 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c concat->mtd.erasesize = max_erasesize; concat->mtd.numeraseregions = num_erase_region; concat->mtd.eraseregions = erase_region_p = - kmalloc(num_erase_region * - sizeof (struct mtd_erase_region_info), GFP_KERNEL); + kmalloc_array(num_erase_region, + sizeof(struct mtd_erase_region_info), + GFP_KERNEL); if (!erase_region_p) { kfree(concat); printk diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c index 9f25111fd559..e078fc41aa61 100644 --- a/drivers/mtd/mtdoops.c +++ b/drivers/mtd/mtdoops.c @@ -330,8 +330,10 @@ static void mtdoops_notify_add(struct mtd_info *mtd) } /* oops_page_used is a bit field */ - cxt->oops_page_used = vmalloc(DIV_ROUND_UP(mtdoops_pages, - BITS_PER_LONG) * sizeof(unsigned long)); + cxt->oops_page_used = + vmalloc(array_size(sizeof(unsigned long), + DIV_ROUND_UP(mtdoops_pages, + BITS_PER_LONG))); if (!cxt->oops_page_used) { printk(KERN_ERR "mtdoops: could not allocate page array\n"); return; diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c index 7161f8a17f62..d9dcb2d051b4 100644 --- a/drivers/mtd/mtdswap.c +++ b/drivers/mtd/mtdswap.c @@ -1317,11 +1317,11 @@ static int mtdswap_init(struct mtdswap_dev *d, unsigned int eblocks, for (i = 0; i < MTDSWAP_TREE_CNT; i++) d->trees[i].root = RB_ROOT; - d->page_data = vmalloc(sizeof(int)*pages); + d->page_data = vmalloc(array_size(pages, sizeof(int))); if (!d->page_data) goto page_data_fail; - d->revmap = vmalloc(sizeof(int)*blocks); + d->revmap = vmalloc(array_size(blocks, sizeof(int))); if (!d->revmap) goto revmap_fail; @@ -1340,7 +1340,7 @@ static int mtdswap_init(struct mtdswap_dev *d, unsigned int eblocks, if (!d->page_buf) goto page_buf_fail; - d->oob_buf = kmalloc(2 * mtd->oobavail, GFP_KERNEL); + d->oob_buf = kmalloc_array(2, mtd->oobavail, GFP_KERNEL); if (!d->oob_buf) goto oob_buf_fail; diff --git a/drivers/mtd/nand/onenand/onenand_base.c b/drivers/mtd/nand/onenand/onenand_base.c index b7105192cb12..4ca4b194e7d7 100644 --- a/drivers/mtd/nand/onenand/onenand_base.c +++ b/drivers/mtd/nand/onenand/onenand_base.c @@ -3721,8 +3721,10 @@ static int onenand_probe(struct mtd_info *mtd) this->dies = ONENAND_IS_DDP(this) ? 2 : 1; /* Maximum possible erase regions */ mtd->numeraseregions = this->dies << 1; - mtd->eraseregions = kzalloc(sizeof(struct mtd_erase_region_info) - * (this->dies << 1), GFP_KERNEL); + mtd->eraseregions = + kcalloc(this->dies << 1, + sizeof(struct mtd_erase_region_info), + GFP_KERNEL); if (!mtd->eraseregions) return -ENOMEM; } diff --git a/drivers/mtd/nand/raw/davinci_nand.c b/drivers/mtd/nand/raw/davinci_nand.c index 7255a0d94374..cd12e5abafde 100644 --- a/drivers/mtd/nand/raw/davinci_nand.c +++ b/drivers/mtd/nand/raw/davinci_nand.c @@ -545,7 +545,7 @@ static struct davinci_nand_pdata return ERR_PTR(-ENOMEM); if (!of_property_read_u32(pdev->dev.of_node, "ti,davinci-chipselect", &prop)) - pdev->id = prop; + pdata->core_chipsel = prop; else return ERR_PTR(-EINVAL); @@ -627,7 +627,7 @@ static int nand_davinci_probe(struct platform_device *pdev) return -ENODEV; /* which external chipselect will we be managing? */ - if (pdev->id < 0 || pdev->id > 3) + if (pdata->core_chipsel < 0 || pdata->core_chipsel > 3) return -ENODEV; info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); @@ -683,7 +683,7 @@ static int nand_davinci_probe(struct platform_device *pdev) info->ioaddr = (uint32_t __force) vaddr; info->current_cs = info->ioaddr; - info->core_chipsel = pdev->id; + info->core_chipsel = pdata->core_chipsel; info->mask_chipsel = pdata->mask_chipsel; /* use nandboot-capable ALE/CLE masks by default */ diff --git a/drivers/mtd/nand/raw/nand_bch.c b/drivers/mtd/nand/raw/nand_bch.c index 7f11b68f6db1..b7387ace567a 100644 --- a/drivers/mtd/nand/raw/nand_bch.c +++ b/drivers/mtd/nand/raw/nand_bch.c @@ -186,7 +186,7 @@ struct nand_bch_control *nand_bch_init(struct mtd_info *mtd) } nbc->eccmask = kmalloc(eccbytes, GFP_KERNEL); - nbc->errloc = kmalloc(t*sizeof(*nbc->errloc), GFP_KERNEL); + nbc->errloc = kmalloc_array(t, sizeof(*nbc->errloc), GFP_KERNEL); if (!nbc->eccmask || !nbc->errloc) goto fail; /* diff --git a/drivers/mtd/nand/raw/nandsim.c b/drivers/mtd/nand/raw/nandsim.c index e027c6f9d327..f8edacde49ab 100644 --- a/drivers/mtd/nand/raw/nandsim.c +++ b/drivers/mtd/nand/raw/nandsim.c @@ -565,8 +565,9 @@ static int __init alloc_device(struct nandsim *ns) err = -EINVAL; goto err_close; } - ns->pages_written = vzalloc(BITS_TO_LONGS(ns->geom.pgnum) * - sizeof(unsigned long)); + ns->pages_written = + vzalloc(array_size(sizeof(unsigned long), + BITS_TO_LONGS(ns->geom.pgnum))); if (!ns->pages_written) { NS_ERR("alloc_device: unable to allocate pages written array\n"); err = -ENOMEM; @@ -582,7 +583,7 @@ static int __init alloc_device(struct nandsim *ns) return 0; } - ns->pages = vmalloc(ns->geom.pgnum * sizeof(union ns_mem)); + ns->pages = vmalloc(array_size(sizeof(union ns_mem), ns->geom.pgnum)); if (!ns->pages) { NS_ERR("alloc_device: unable to allocate page array\n"); return -ENOMEM; diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c index b554fb6e609c..6a5519f0ff25 100644 --- a/drivers/mtd/nand/raw/qcom_nandc.c +++ b/drivers/mtd/nand/raw/qcom_nandc.c @@ -2510,8 +2510,8 @@ static int qcom_nandc_alloc(struct qcom_nand_controller *nandc) if (!nandc->regs) return -ENOMEM; - nandc->reg_read_buf = devm_kzalloc(nandc->dev, - MAX_REG_RD * sizeof(*nandc->reg_read_buf), + nandc->reg_read_buf = devm_kcalloc(nandc->dev, + MAX_REG_RD, sizeof(*nandc->reg_read_buf), GFP_KERNEL); if (!nandc->reg_read_buf) return -ENOMEM; diff --git a/drivers/mtd/nand/raw/s3c2410.c b/drivers/mtd/nand/raw/s3c2410.c index 1bc0458063d8..19661c5d3220 100644 --- a/drivers/mtd/nand/raw/s3c2410.c +++ b/drivers/mtd/nand/raw/s3c2410.c @@ -1038,7 +1038,7 @@ static int s3c24xx_nand_probe_dt(struct platform_device *pdev) if (!pdata->nr_sets) return 0; - sets = devm_kzalloc(&pdev->dev, sizeof(*sets) * pdata->nr_sets, + sets = devm_kcalloc(&pdev->dev, pdata->nr_sets, sizeof(*sets), GFP_KERNEL); if (!sets) return -ENOMEM; diff --git a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c index 6281da3dadac..27184e3874db 100644 --- a/drivers/mtd/nftlmount.c +++ b/drivers/mtd/nftlmount.c @@ -199,13 +199,16 @@ device is already correct. nftl->lastEUN = nftl->nb_blocks - 1; /* memory alloc */ - nftl->EUNtable = kmalloc(nftl->nb_blocks * sizeof(u16), GFP_KERNEL); + nftl->EUNtable = kmalloc_array(nftl->nb_blocks, sizeof(u16), + GFP_KERNEL); if (!nftl->EUNtable) { printk(KERN_NOTICE "NFTL: allocation of EUNtable failed\n"); return -ENOMEM; } - nftl->ReplUnitTable = kmalloc(nftl->nb_blocks * sizeof(u16), GFP_KERNEL); + nftl->ReplUnitTable = kmalloc_array(nftl->nb_blocks, + sizeof(u16), + GFP_KERNEL); if (!nftl->ReplUnitTable) { kfree(nftl->EUNtable); printk(KERN_NOTICE "NFTL: allocation of ReplUnitTable failed\n"); diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c index 615f8c173162..6b21a92d3622 100644 --- a/drivers/mtd/ofpart.c +++ b/drivers/mtd/ofpart.c @@ -71,7 +71,7 @@ static int parse_fixed_partitions(struct mtd_info *master, if (nr_parts == 0) return 0; - parts = kzalloc(nr_parts * sizeof(*parts), GFP_KERNEL); + parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL); if (!parts) return -ENOMEM; @@ -177,7 +177,7 @@ static int parse_ofoldpart_partitions(struct mtd_info *master, nr_parts = plen / sizeof(part[0]); - parts = kzalloc(nr_parts * sizeof(*parts), GFP_KERNEL); + parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL); if (!parts) return -ENOMEM; diff --git a/drivers/mtd/parsers/parser_trx.c b/drivers/mtd/parsers/parser_trx.c index df360a75e1eb..17ac33599783 100644 --- a/drivers/mtd/parsers/parser_trx.c +++ b/drivers/mtd/parsers/parser_trx.c @@ -62,7 +62,7 @@ static int parser_trx_parse(struct mtd_info *mtd, uint8_t curr_part = 0, i = 0; int err; - parts = kzalloc(sizeof(struct mtd_partition) * TRX_PARSER_MAX_PARTS, + parts = kcalloc(TRX_PARSER_MAX_PARTS, sizeof(struct mtd_partition), GFP_KERNEL); if (!parts) return -ENOMEM; diff --git a/drivers/mtd/parsers/sharpslpart.c b/drivers/mtd/parsers/sharpslpart.c index 8893dc82a5c8..e5ea6127ab5a 100644 --- a/drivers/mtd/parsers/sharpslpart.c +++ b/drivers/mtd/parsers/sharpslpart.c @@ -362,8 +362,9 @@ static int sharpsl_parse_mtd_partitions(struct mtd_info *master, return err; } - sharpsl_nand_parts = kzalloc(sizeof(*sharpsl_nand_parts) * - SHARPSL_NAND_PARTS, GFP_KERNEL); + sharpsl_nand_parts = kcalloc(SHARPSL_NAND_PARTS, + sizeof(*sharpsl_nand_parts), + GFP_KERNEL); if (!sharpsl_nand_parts) return -ENOMEM; diff --git a/drivers/mtd/rfd_ftl.c b/drivers/mtd/rfd_ftl.c index df27f24ce0fa..94720f2ca9a8 100644 --- a/drivers/mtd/rfd_ftl.c +++ b/drivers/mtd/rfd_ftl.c @@ -189,7 +189,8 @@ static int scan_header(struct partition *part) if (!part->blocks) goto err; - part->sector_map = vmalloc(part->sector_count * sizeof(u_long)); + part->sector_map = vmalloc(array_size(sizeof(u_long), + part->sector_count)); if (!part->sector_map) { printk(KERN_ERR PREFIX "'%s': unable to allocate memory for " "sector map", part->mbd.mtd->name); diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c index 79636349df96..f3bd86e13603 100644 --- a/drivers/mtd/sm_ftl.c +++ b/drivers/mtd/sm_ftl.c @@ -82,7 +82,7 @@ static struct attribute_group *sm_create_sysfs_attributes(struct sm_ftl *ftl) /* Create array of pointers to the attributes */ - attributes = kzalloc(sizeof(struct attribute *) * (NUM_ATTRIBUTES + 1), + attributes = kcalloc(NUM_ATTRIBUTES + 1, sizeof(struct attribute *), GFP_KERNEL); if (!attributes) goto error3; @@ -750,7 +750,7 @@ static int sm_init_zone(struct sm_ftl *ftl, int zone_num) dbg("initializing zone %d", zone_num); /* Allocate memory for FTL table */ - zone->lba_to_phys_table = kmalloc(ftl->max_lba * 2, GFP_KERNEL); + zone->lba_to_phys_table = kmalloc_array(ftl->max_lba, 2, GFP_KERNEL); if (!zone->lba_to_phys_table) return -ENOMEM; @@ -1137,7 +1137,7 @@ static void sm_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) goto error2; /* Allocate zone array, it will be initialized on demand */ - ftl->zones = kzalloc(sizeof(struct ftl_zone) * ftl->zone_count, + ftl->zones = kcalloc(ftl->zone_count, sizeof(struct ftl_zone), GFP_KERNEL); if (!ftl->zones) goto error3; diff --git a/drivers/mtd/ssfdc.c b/drivers/mtd/ssfdc.c index 95f0bf95f095..7a1e54546f4a 100644 --- a/drivers/mtd/ssfdc.c +++ b/drivers/mtd/ssfdc.c @@ -332,8 +332,9 @@ static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) (long)ssfdc->sectors; /* Allocate logical block map */ - ssfdc->logic_block_map = kmalloc(sizeof(ssfdc->logic_block_map[0]) * - ssfdc->map_len, GFP_KERNEL); + ssfdc->logic_block_map = + kmalloc_array(ssfdc->map_len, + sizeof(ssfdc->logic_block_map[0]), GFP_KERNEL); if (!ssfdc->logic_block_map) goto out_err; memset(ssfdc->logic_block_map, 0xff, sizeof(ssfdc->logic_block_map[0]) * diff --git a/drivers/mtd/tests/pagetest.c b/drivers/mtd/tests/pagetest.c index bc303cac9f43..75687369bc20 100644 --- a/drivers/mtd/tests/pagetest.c +++ b/drivers/mtd/tests/pagetest.c @@ -127,7 +127,7 @@ static int crosstest(void) unsigned char *pp1, *pp2, *pp3, *pp4; pr_info("crosstest\n"); - pp1 = kzalloc(pgsize * 4, GFP_KERNEL); + pp1 = kcalloc(pgsize, 4, GFP_KERNEL); if (!pp1) return -ENOMEM; pp2 = pp1 + pgsize; diff --git a/drivers/mtd/tests/stresstest.c b/drivers/mtd/tests/stresstest.c index e509f8aa9a7e..0fe1217f94b9 100644 --- a/drivers/mtd/tests/stresstest.c +++ b/drivers/mtd/tests/stresstest.c @@ -199,7 +199,7 @@ static int __init mtd_stresstest_init(void) err = -ENOMEM; readbuf = vmalloc(bufsize); writebuf = vmalloc(bufsize); - offsets = kmalloc(ebcnt * sizeof(int), GFP_KERNEL); + offsets = kmalloc_array(ebcnt, sizeof(int), GFP_KERNEL); if (!readbuf || !writebuf || !offsets) goto out; for (i = 0; i < ebcnt; i++) diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index edb1c8362faa..b98481b69314 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -1536,11 +1536,11 @@ int self_check_eba(struct ubi_device *ubi, struct ubi_attach_info *ai_fastmap, num_volumes = ubi->vtbl_slots + UBI_INT_VOL_COUNT; - scan_eba = kmalloc(sizeof(*scan_eba) * num_volumes, GFP_KERNEL); + scan_eba = kmalloc_array(num_volumes, sizeof(*scan_eba), GFP_KERNEL); if (!scan_eba) return -ENOMEM; - fm_eba = kmalloc(sizeof(*fm_eba) * num_volumes, GFP_KERNEL); + fm_eba = kmalloc_array(num_volumes, sizeof(*fm_eba), GFP_KERNEL); if (!fm_eba) { kfree(scan_eba); return -ENOMEM; @@ -1551,15 +1551,17 @@ int self_check_eba(struct ubi_device *ubi, struct ubi_attach_info *ai_fastmap, if (!vol) continue; - scan_eba[i] = kmalloc(vol->reserved_pebs * sizeof(**scan_eba), - GFP_KERNEL); + scan_eba[i] = kmalloc_array(vol->reserved_pebs, + sizeof(**scan_eba), + GFP_KERNEL); if (!scan_eba[i]) { ret = -ENOMEM; goto out_free; } - fm_eba[i] = kmalloc(vol->reserved_pebs * sizeof(**fm_eba), - GFP_KERNEL); + fm_eba[i] = kmalloc_array(vol->reserved_pebs, + sizeof(**fm_eba), + GFP_KERNEL); if (!fm_eba[i]) { ret = -ENOMEM; goto out_free; diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index f66b3b22f328..6f2ac865ff05 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -1592,7 +1592,7 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai) sprintf(ubi->bgt_name, UBI_BGT_NAME_PATTERN, ubi->ubi_num); err = -ENOMEM; - ubi->lookuptbl = kzalloc(ubi->peb_count * sizeof(void *), GFP_KERNEL); + ubi->lookuptbl = kcalloc(ubi->peb_count, sizeof(void *), GFP_KERNEL); if (!ubi->lookuptbl) return err; diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index bd53a71f6b00..63e3844c5bec 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2418,7 +2418,7 @@ struct bond_vlan_tag *bond_verify_device_path(struct net_device *start_dev, struct list_head *iter; if (start_dev == end_dev) { - tags = kzalloc(sizeof(*tags) * (level + 1), GFP_ATOMIC); + tags = kcalloc(level + 1, sizeof(*tags), GFP_ATOMIC); if (!tags) return ERR_PTR(-ENOMEM); tags[level].vlan_proto = VLAN_N_VID; diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c index 2d3046afa80d..7eec1d9f86a0 100644 --- a/drivers/net/can/grcan.c +++ b/drivers/net/can/grcan.c @@ -1057,7 +1057,7 @@ static int grcan_open(struct net_device *dev) return err; } - priv->echo_skb = kzalloc(dma->tx.size * sizeof(*priv->echo_skb), + priv->echo_skb = kcalloc(dma->tx.size, sizeof(*priv->echo_skb), GFP_KERNEL); if (!priv->echo_skb) { err = -ENOMEM; @@ -1066,7 +1066,7 @@ static int grcan_open(struct net_device *dev) priv->can.echo_skb_max = dma->tx.size; priv->can.echo_skb = priv->echo_skb; - priv->txdlc = kzalloc(dma->tx.size * sizeof(*priv->txdlc), GFP_KERNEL); + priv->txdlc = kcalloc(dma->tx.size, sizeof(*priv->txdlc), GFP_KERNEL); if (!priv->txdlc) { err = -ENOMEM; goto exit_free_echo_skb; diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c index 89d60d8e467c..aa97dbc797b6 100644 --- a/drivers/net/can/slcan.c +++ b/drivers/net/can/slcan.c @@ -703,7 +703,7 @@ static int __init slcan_init(void) pr_info("slcan: serial line CAN interface driver\n"); pr_info("slcan: %d dynamic interface channels.\n", maxdev); - slcan_devs = kzalloc(sizeof(struct net_device *)*maxdev, GFP_KERNEL); + slcan_devs = kcalloc(maxdev, sizeof(struct net_device *), GFP_KERNEL); if (!slcan_devs) return -ENOMEM; diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 5e010b1592f7..d93c790bfbe8 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -2044,14 +2044,14 @@ static int b53_switch_init(struct b53_device *dev) } } - dev->ports = devm_kzalloc(dev->dev, - sizeof(struct b53_port) * dev->num_ports, + dev->ports = devm_kcalloc(dev->dev, + dev->num_ports, sizeof(struct b53_port), GFP_KERNEL); if (!dev->ports) return -ENOMEM; - dev->vlans = devm_kzalloc(dev->dev, - sizeof(struct b53_vlan) * dev->num_vlans, + dev->vlans = devm_kcalloc(dev->dev, + dev->num_vlans, sizeof(struct b53_vlan), GFP_KERNEL); if (!dev->vlans) return -ENOMEM; diff --git a/drivers/net/ethernet/amazon/ena/ena_ethtool.c b/drivers/net/ethernet/amazon/ena/ena_ethtool.c index 060cb18fa659..521607bc4393 100644 --- a/drivers/net/ethernet/amazon/ena/ena_ethtool.c +++ b/drivers/net/ethernet/amazon/ena/ena_ethtool.c @@ -838,8 +838,8 @@ static void ena_dump_stats_ex(struct ena_adapter *adapter, u8 *buf) return; } - strings_buf = devm_kzalloc(&adapter->pdev->dev, - strings_num * ETH_GSTRING_LEN, + strings_buf = devm_kcalloc(&adapter->pdev->dev, + ETH_GSTRING_LEN, strings_num, GFP_ATOMIC); if (!strings_buf) { netif_err(adapter, drv, netdev, @@ -847,8 +847,8 @@ static void ena_dump_stats_ex(struct ena_adapter *adapter, u8 *buf) return; } - data_buf = devm_kzalloc(&adapter->pdev->dev, - strings_num * sizeof(u64), + data_buf = devm_kcalloc(&adapter->pdev->dev, + strings_num, sizeof(u64), GFP_ATOMIC); if (!data_buf) { netif_err(adapter, drv, netdev, diff --git a/drivers/net/ethernet/amd/lance.c b/drivers/net/ethernet/amd/lance.c index 12a6a93d221b..b56d84c7df46 100644 --- a/drivers/net/ethernet/amd/lance.c +++ b/drivers/net/ethernet/amd/lance.c @@ -551,13 +551,13 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int if (lance_debug > 6) printk(" (#0x%05lx)", (unsigned long)lp); dev->ml_priv = lp; lp->name = chipname; - lp->rx_buffs = (unsigned long)kmalloc(PKT_BUF_SZ*RX_RING_SIZE, - GFP_DMA | GFP_KERNEL); + lp->rx_buffs = (unsigned long)kmalloc_array(RX_RING_SIZE, PKT_BUF_SZ, + GFP_DMA | GFP_KERNEL); if (!lp->rx_buffs) goto out_lp; if (lance_need_isa_bounce_buffers) { - lp->tx_bounce_buffs = kmalloc(PKT_BUF_SZ*TX_RING_SIZE, - GFP_DMA | GFP_KERNEL); + lp->tx_bounce_buffs = kmalloc_array(TX_RING_SIZE, PKT_BUF_SZ, + GFP_DMA | GFP_KERNEL); if (!lp->tx_bounce_buffs) goto out_rx; } else diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_ethtool.c b/drivers/net/ethernet/atheros/atl1c/atl1c_ethtool.c index cfe86a20c899..28e9ae1a193b 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_ethtool.c +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_ethtool.c @@ -209,8 +209,8 @@ static int atl1c_get_eeprom(struct net_device *netdev, first_dword = eeprom->offset >> 2; last_dword = (eeprom->offset + eeprom->len - 1) >> 2; - eeprom_buff = kmalloc(sizeof(u32) * - (last_dword - first_dword + 1), GFP_KERNEL); + eeprom_buff = kmalloc_array(last_dword - first_dword + 1, sizeof(u32), + GFP_KERNEL); if (eeprom_buff == NULL) return -ENOMEM; diff --git a/drivers/net/ethernet/atheros/atl1e/atl1e_ethtool.c b/drivers/net/ethernet/atheros/atl1e/atl1e_ethtool.c index cb489e7e8374..282ebdde4769 100644 --- a/drivers/net/ethernet/atheros/atl1e/atl1e_ethtool.c +++ b/drivers/net/ethernet/atheros/atl1e/atl1e_ethtool.c @@ -236,8 +236,8 @@ static int atl1e_get_eeprom(struct net_device *netdev, first_dword = eeprom->offset >> 2; last_dword = (eeprom->offset + eeprom->len - 1) >> 2; - eeprom_buff = kmalloc(sizeof(u32) * - (last_dword - first_dword + 1), GFP_KERNEL); + eeprom_buff = kmalloc_array(last_dword - first_dword + 1, sizeof(u32), + GFP_KERNEL); if (eeprom_buff == NULL) return -ENOMEM; diff --git a/drivers/net/ethernet/atheros/atlx/atl2.c b/drivers/net/ethernet/atheros/atlx/atl2.c index db4bcc51023a..bb41becb6609 100644 --- a/drivers/net/ethernet/atheros/atlx/atl2.c +++ b/drivers/net/ethernet/atheros/atlx/atl2.c @@ -1941,8 +1941,8 @@ static int atl2_get_eeprom(struct net_device *netdev, first_dword = eeprom->offset >> 2; last_dword = (eeprom->offset + eeprom->len - 1) >> 2; - eeprom_buff = kmalloc(sizeof(u32) * (last_dword - first_dword + 1), - GFP_KERNEL); + eeprom_buff = kmalloc_array(last_dword - first_dword + 1, sizeof(u32), + GFP_KERNEL); if (!eeprom_buff) return -ENOMEM; diff --git a/drivers/net/ethernet/broadcom/bcm63xx_enet.c b/drivers/net/ethernet/broadcom/bcm63xx_enet.c index 14a59e51db67..897302adc38e 100644 --- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c +++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c @@ -2150,7 +2150,7 @@ static int bcm_enetsw_open(struct net_device *dev) priv->tx_desc_alloc_size = size; priv->tx_desc_cpu = p; - priv->tx_skb = kzalloc(sizeof(struct sk_buff *) * priv->tx_ring_size, + priv->tx_skb = kcalloc(priv->tx_ring_size, sizeof(struct sk_buff *), GFP_KERNEL); if (!priv->tx_skb) { dev_err(kdev, "cannot allocate rx skb queue\n"); @@ -2164,7 +2164,7 @@ static int bcm_enetsw_open(struct net_device *dev) spin_lock_init(&priv->tx_lock); /* init & fill rx ring with skbs */ - priv->rx_skb = kzalloc(sizeof(struct sk_buff *) * priv->rx_ring_size, + priv->rx_skb = kcalloc(priv->rx_ring_size, sizeof(struct sk_buff *), GFP_KERNEL); if (!priv->rx_skb) { dev_err(kdev, "cannot allocate rx skb queue\n"); diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c index 3853296d78c1..122fdb80a789 100644 --- a/drivers/net/ethernet/broadcom/bnx2.c +++ b/drivers/net/ethernet/broadcom/bnx2.c @@ -778,7 +778,7 @@ bnx2_alloc_rx_mem(struct bnx2 *bp) int j; rxr->rx_buf_ring = - vzalloc(SW_RXBD_RING_SIZE * bp->rx_max_ring); + vzalloc(array_size(SW_RXBD_RING_SIZE, bp->rx_max_ring)); if (!rxr->rx_buf_ring) return -ENOMEM; @@ -794,8 +794,9 @@ bnx2_alloc_rx_mem(struct bnx2 *bp) } if (bp->rx_pg_ring_size) { - rxr->rx_pg_ring = vzalloc(SW_RXPG_RING_SIZE * - bp->rx_max_pg_ring); + rxr->rx_pg_ring = + vzalloc(array_size(SW_RXPG_RING_SIZE, + bp->rx_max_pg_ring)); if (!rxr->rx_pg_ring) return -ENOMEM; @@ -2666,7 +2667,7 @@ bnx2_alloc_bad_rbuf(struct bnx2 *bp) u32 good_mbuf_cnt; u32 val; - good_mbuf = kmalloc(512 * sizeof(u16), GFP_KERNEL); + good_mbuf = kmalloc_array(512, sizeof(u16), GFP_KERNEL); if (!good_mbuf) return -ENOMEM; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c index ffa7959f6b31..dc77bfded865 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c @@ -571,7 +571,7 @@ int bnx2x_vf_mcast(struct bnx2x *bp, struct bnx2x_virtf *vf, else set_bit(RAMROD_COMP_WAIT, &mcast.ramrod_flags); if (mc_num) { - mc = kzalloc(mc_num * sizeof(struct bnx2x_mcast_list_elem), + mc = kcalloc(mc_num, sizeof(struct bnx2x_mcast_list_elem), GFP_KERNEL); if (!mc) { BNX2X_ERR("Cannot Configure multicasts due to lack of memory\n"); @@ -1253,8 +1253,9 @@ int bnx2x_iov_init_one(struct bnx2x *bp, int int_mode_param, num_vfs_param, iov->nr_virtfn); /* allocate the vf array */ - bp->vfdb->vfs = kzalloc(sizeof(struct bnx2x_virtf) * - BNX2X_NR_VIRTFN(bp), GFP_KERNEL); + bp->vfdb->vfs = kcalloc(BNX2X_NR_VIRTFN(bp), + sizeof(struct bnx2x_virtf), + GFP_KERNEL); if (!bp->vfdb->vfs) { BNX2X_ERR("failed to allocate vf array\n"); err = -ENOMEM; @@ -1278,9 +1279,9 @@ int bnx2x_iov_init_one(struct bnx2x *bp, int int_mode_param, } /* allocate the queue arrays for all VFs */ - bp->vfdb->vfqs = kzalloc( - BNX2X_MAX_NUM_VF_QUEUES * sizeof(struct bnx2x_vf_queue), - GFP_KERNEL); + bp->vfdb->vfqs = kcalloc(BNX2X_MAX_NUM_VF_QUEUES, + sizeof(struct bnx2x_vf_queue), + GFP_KERNEL); if (!bp->vfdb->vfqs) { BNX2X_ERR("failed to allocate vf queue array\n"); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c index 38f635cf8408..05d405905906 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c @@ -444,8 +444,8 @@ static int bnxt_vf_reps_create(struct bnxt *bp) return -ENOMEM; /* storage for cfa_code to vf-idx mapping */ - cfa_code_map = kmalloc(sizeof(*bp->cfa_code_map) * MAX_CFA_CODE, - GFP_KERNEL); + cfa_code_map = kmalloc_array(MAX_CFA_CODE, sizeof(*bp->cfa_code_map), + GFP_KERNEL); if (!cfa_code_map) { rc = -ENOMEM; goto err; diff --git a/drivers/net/ethernet/broadcom/cnic.c b/drivers/net/ethernet/broadcom/cnic.c index 8bc126a156e8..30273a7717e2 100644 --- a/drivers/net/ethernet/broadcom/cnic.c +++ b/drivers/net/ethernet/broadcom/cnic.c @@ -660,7 +660,7 @@ static int cnic_init_id_tbl(struct cnic_id_tbl *id_tbl, u32 size, u32 start_id, id_tbl->max = size; id_tbl->next = next; spin_lock_init(&id_tbl->lock); - id_tbl->table = kzalloc(DIV_ROUND_UP(size, 32) * 4, GFP_KERNEL); + id_tbl->table = kcalloc(DIV_ROUND_UP(size, 32), 4, GFP_KERNEL); if (!id_tbl->table) return -ENOMEM; @@ -1255,13 +1255,13 @@ static int cnic_alloc_bnx2x_resc(struct cnic_dev *dev) cp->fcoe_init_cid = 0x10; } - cp->iscsi_tbl = kzalloc(sizeof(struct cnic_iscsi) * MAX_ISCSI_TBL_SZ, + cp->iscsi_tbl = kcalloc(MAX_ISCSI_TBL_SZ, sizeof(struct cnic_iscsi), GFP_KERNEL); if (!cp->iscsi_tbl) goto error; - cp->ctx_tbl = kzalloc(sizeof(struct cnic_context) * - cp->max_cid_space, GFP_KERNEL); + cp->ctx_tbl = kcalloc(cp->max_cid_space, sizeof(struct cnic_context), + GFP_KERNEL); if (!cp->ctx_tbl) goto error; @@ -4100,7 +4100,7 @@ static int cnic_cm_alloc_mem(struct cnic_dev *dev) struct cnic_local *cp = dev->cnic_priv; u32 port_id; - cp->csk_tbl = kzalloc(sizeof(struct cnic_sock) * MAX_CM_SK_TBL_SZ, + cp->csk_tbl = kcalloc(MAX_CM_SK_TBL_SZ, sizeof(struct cnic_sock), GFP_KERNEL); if (!cp->csk_tbl) return -ENOMEM; diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 9f59b1270a7c..3be87efdc93d 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -8631,8 +8631,9 @@ static int tg3_mem_tx_acquire(struct tg3 *tp) tnapi++; for (i = 0; i < tp->txq_cnt; i++, tnapi++) { - tnapi->tx_buffers = kzalloc(sizeof(struct tg3_tx_ring_info) * - TG3_TX_RING_SIZE, GFP_KERNEL); + tnapi->tx_buffers = kcalloc(TG3_TX_RING_SIZE, + sizeof(struct tg3_tx_ring_info), + GFP_KERNEL); if (!tnapi->tx_buffers) goto err_out; diff --git a/drivers/net/ethernet/brocade/bna/bnad.c b/drivers/net/ethernet/brocade/bna/bnad.c index 69cc3e0119d6..ea5f32ea308a 100644 --- a/drivers/net/ethernet/brocade/bna/bnad.c +++ b/drivers/net/ethernet/brocade/bna/bnad.c @@ -3141,7 +3141,7 @@ bnad_set_rx_ucast_fltr(struct bnad *bnad) if (uc_count > bna_attr(&bnad->bna)->num_ucmac) goto mode_default; - mac_list = kzalloc(uc_count * ETH_ALEN, GFP_ATOMIC); + mac_list = kcalloc(ETH_ALEN, uc_count, GFP_ATOMIC); if (mac_list == NULL) goto mode_default; @@ -3182,7 +3182,7 @@ bnad_set_rx_mcast_fltr(struct bnad *bnad) if (mc_count > bna_attr(&bnad->bna)->num_mcmac) goto mode_allmulti; - mac_list = kzalloc((mc_count + 1) * ETH_ALEN, GFP_ATOMIC); + mac_list = kcalloc(mc_count + 1, ETH_ALEN, GFP_ATOMIC); if (mac_list == NULL) goto mode_allmulti; diff --git a/drivers/net/ethernet/calxeda/xgmac.c b/drivers/net/ethernet/calxeda/xgmac.c index 2bd7c638b178..2c63afff1382 100644 --- a/drivers/net/ethernet/calxeda/xgmac.c +++ b/drivers/net/ethernet/calxeda/xgmac.c @@ -739,7 +739,7 @@ static int xgmac_dma_desc_rings_init(struct net_device *dev) netdev_dbg(priv->dev, "mtu [%d] bfsize [%d]\n", dev->mtu, bfsize); - priv->rx_skbuff = kzalloc(sizeof(struct sk_buff *) * DMA_RX_RING_SZ, + priv->rx_skbuff = kcalloc(DMA_RX_RING_SZ, sizeof(struct sk_buff *), GFP_KERNEL); if (!priv->rx_skbuff) return -ENOMEM; @@ -752,7 +752,7 @@ static int xgmac_dma_desc_rings_init(struct net_device *dev) if (!priv->dma_rx) goto err_dma_rx; - priv->tx_skbuff = kzalloc(sizeof(struct sk_buff *) * DMA_TX_RING_SZ, + priv->tx_skbuff = kcalloc(DMA_TX_RING_SZ, sizeof(struct sk_buff *), GFP_KERNEL); if (!priv->tx_skbuff) goto err_tx_skb; diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_droq.c b/drivers/net/ethernet/cavium/liquidio/octeon_droq.c index f044718cea52..a71dbb7ab6af 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_droq.c +++ b/drivers/net/ethernet/cavium/liquidio/octeon_droq.c @@ -281,13 +281,12 @@ int octeon_init_droq(struct octeon_device *oct, droq->max_count); droq->recv_buf_list = (struct octeon_recv_buffer *) - vzalloc_node(droq->max_count * - OCT_DROQ_RECVBUF_SIZE, - numa_node); + vzalloc_node(array_size(droq->max_count, OCT_DROQ_RECVBUF_SIZE), + numa_node); if (!droq->recv_buf_list) droq->recv_buf_list = (struct octeon_recv_buffer *) - vzalloc(droq->max_count * - OCT_DROQ_RECVBUF_SIZE); + vzalloc(array_size(droq->max_count, + OCT_DROQ_RECVBUF_SIZE)); if (!droq->recv_buf_list) { dev_err(&oct->pci_dev->dev, "Output queue recv buf list alloc failed\n"); goto init_droq_fail; diff --git a/drivers/net/ethernet/cavium/liquidio/request_manager.c b/drivers/net/ethernet/cavium/liquidio/request_manager.c index b1270355b0b1..1f2e75da28f8 100644 --- a/drivers/net/ethernet/cavium/liquidio/request_manager.c +++ b/drivers/net/ethernet/cavium/liquidio/request_manager.c @@ -98,8 +98,9 @@ int octeon_init_instr_queue(struct octeon_device *oct, iq->request_list = vmalloc_node((sizeof(*iq->request_list) * num_descs), numa_node); if (!iq->request_list) - iq->request_list = vmalloc(sizeof(*iq->request_list) * - num_descs); + iq->request_list = + vmalloc(array_size(num_descs, + sizeof(*iq->request_list))); if (!iq->request_list) { lio_dma_free(oct, q_size, iq->base_addr, iq->base_addr_dma); dev_err(&oct->pci_dev->dev, "Alloc failed for IQ[%d] nr free list\n", diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c index d42704d07484..187a249ff2d1 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c @@ -292,8 +292,8 @@ static int nicvf_init_rbdr(struct nicvf *nic, struct rbdr *rbdr, rbdr->is_xdp = true; } rbdr->pgcnt = roundup_pow_of_two(rbdr->pgcnt); - rbdr->pgcache = kzalloc(sizeof(*rbdr->pgcache) * - rbdr->pgcnt, GFP_KERNEL); + rbdr->pgcache = kcalloc(rbdr->pgcnt, sizeof(*rbdr->pgcache), + GFP_KERNEL); if (!rbdr->pgcache) return -ENOMEM; rbdr->pgidx = 0; diff --git a/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c index 290039026ece..5701272aa7f7 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c +++ b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c @@ -304,7 +304,7 @@ struct clip_tbl *t4_init_clip_tbl(unsigned int clipt_start, for (i = 0; i < ctbl->clipt_size; ++i) INIT_LIST_HEAD(&ctbl->hash_list[i]); - cl_list = kvzalloc(clipt_size*sizeof(struct clip_entry), GFP_KERNEL); + cl_list = kvcalloc(clipt_size, sizeof(struct clip_entry), GFP_KERNEL); if (!cl_list) { kvfree(ctbl); return NULL; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c index 251d5bdc972f..c301aaf79d64 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c @@ -873,7 +873,7 @@ static int cctrl_tbl_show(struct seq_file *seq, void *v) u16 (*incr)[NCCTRL_WIN]; struct adapter *adap = seq->private; - incr = kmalloc(sizeof(*incr) * NMTUS, GFP_KERNEL); + incr = kmalloc_array(NMTUS, sizeof(*incr), GFP_KERNEL); if (!incr) return -ENOMEM; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 35cb3ae4f7b6..dd04a2f89ce6 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -713,7 +713,7 @@ int cxgb4_write_rss(const struct port_info *pi, const u16 *queues) const struct sge_eth_rxq *rxq; rxq = &adapter->sge.ethrxq[pi->first_qset]; - rss = kmalloc(pi->rss_size * sizeof(u16), GFP_KERNEL); + rss = kmalloc_array(pi->rss_size, sizeof(u16), GFP_KERNEL); if (!rss) return -ENOMEM; @@ -4972,8 +4972,8 @@ static int enable_msix(struct adapter *adap) max_ingq += (MAX_OFLD_QSETS * adap->num_uld); if (is_offload(adap)) max_ingq += (MAX_OFLD_QSETS * adap->num_ofld_uld); - entries = kmalloc(sizeof(*entries) * (max_ingq + 1), - GFP_KERNEL); + entries = kmalloc_array(max_ingq + 1, sizeof(*entries), + GFP_KERNEL); if (!entries) return -ENOMEM; @@ -5646,8 +5646,8 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) adapter->params.offload = 0; } - adapter->mps_encap = kvzalloc(sizeof(struct mps_encap_entry) * - adapter->params.arch.mps_tcam_size, + adapter->mps_encap = kvcalloc(adapter->params.arch.mps_tcam_size, + sizeof(struct mps_encap_entry), GFP_KERNEL); if (!adapter->mps_encap) dev_warn(&pdev->dev, "could not allocate MPS Encap entries, continuing\n"); diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_u32.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_u32.c index ab174bcfbfb0..18eb2aedd4cb 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_u32.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_u32.c @@ -457,7 +457,8 @@ struct cxgb4_tc_u32_table *cxgb4_init_tc_u32(struct adapter *adap) unsigned int bmap_size; bmap_size = BITS_TO_LONGS(max_tids); - link->tid_map = kvzalloc(sizeof(unsigned long) * bmap_size, GFP_KERNEL); + link->tid_map = kvcalloc(bmap_size, sizeof(unsigned long), + GFP_KERNEL); if (!link->tid_map) goto out_no_mem; bitmap_zero(link->tid_map, max_tids); diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c index a95cde0fadf7..4bc211093c98 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c @@ -561,13 +561,13 @@ int t4_uld_mem_alloc(struct adapter *adap) if (!adap->uld) return -ENOMEM; - s->uld_rxq_info = kzalloc(CXGB4_ULD_MAX * + s->uld_rxq_info = kcalloc(CXGB4_ULD_MAX, sizeof(struct sge_uld_rxq_info *), GFP_KERNEL); if (!s->uld_rxq_info) goto err_uld; - s->uld_txq_info = kzalloc(CXGB4_TX_MAX * + s->uld_txq_info = kcalloc(CXGB4_TX_MAX, sizeof(struct sge_uld_txq_info *), GFP_KERNEL); if (!s->uld_txq_info) diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index 7a271feec5e7..395e2a0e8d7f 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -699,7 +699,7 @@ static void *alloc_ring(struct device *dev, size_t nelem, size_t elem_size, if (!p) return NULL; if (sw_size) { - s = kzalloc_node(nelem * sw_size, GFP_KERNEL, node); + s = kcalloc_node(sw_size, nelem, GFP_KERNEL, node); if (!s) { dma_free_coherent(dev, len, p, *phys); diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c index ff9eb45f67f8..6d7404f66f84 100644 --- a/drivers/net/ethernet/cortina/gemini.c +++ b/drivers/net/ethernet/cortina/gemini.c @@ -910,8 +910,8 @@ static int geth_setup_freeq(struct gemini_ethernet *geth) } /* Allocate a mapping to page look-up index */ - geth->freeq_pages = kzalloc(pages * sizeof(*geth->freeq_pages), - GFP_KERNEL); + geth->freeq_pages = kcalloc(pages, sizeof(*geth->freeq_pages), + GFP_KERNEL); if (!geth->freeq_pages) goto err_freeq; geth->num_freeq_pages = pages; diff --git a/drivers/net/ethernet/ethoc.c b/drivers/net/ethernet/ethoc.c index 00a57273b753..60da0499ad66 100644 --- a/drivers/net/ethernet/ethoc.c +++ b/drivers/net/ethernet/ethoc.c @@ -1141,7 +1141,8 @@ static int ethoc_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "ethoc: num_tx: %d num_rx: %d\n", priv->num_tx, priv->num_rx); - priv->vma = devm_kzalloc(&pdev->dev, num_bd*sizeof(void *), GFP_KERNEL); + priv->vma = devm_kcalloc(&pdev->dev, num_bd, sizeof(void *), + GFP_KERNEL); if (!priv->vma) { ret = -ENOMEM; goto free; diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c index fd43f98ddbe7..5f4e1ffa7b95 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c @@ -664,7 +664,7 @@ static struct dpaa_fq *dpaa_fq_alloc(struct device *dev, struct dpaa_fq *dpaa_fq; int i; - dpaa_fq = devm_kzalloc(dev, sizeof(*dpaa_fq) * count, + dpaa_fq = devm_kcalloc(dev, count, sizeof(*dpaa_fq), GFP_KERNEL); if (!dpaa_fq) return NULL; diff --git a/drivers/net/ethernet/freescale/ucc_geth.c b/drivers/net/ethernet/freescale/ucc_geth.c index a96b838cffce..42fca3208c0b 100644 --- a/drivers/net/ethernet/freescale/ucc_geth.c +++ b/drivers/net/ethernet/freescale/ucc_geth.c @@ -2253,9 +2253,9 @@ static int ucc_geth_alloc_tx(struct ucc_geth_private *ugeth) /* Init Tx bds */ for (j = 0; j < ug_info->numQueuesTx; j++) { /* Setup the skbuff rings */ - ugeth->tx_skbuff[j] = kmalloc(sizeof(struct sk_buff *) * - ugeth->ug_info->bdRingLenTx[j], - GFP_KERNEL); + ugeth->tx_skbuff[j] = + kmalloc_array(ugeth->ug_info->bdRingLenTx[j], + sizeof(struct sk_buff *), GFP_KERNEL); if (ugeth->tx_skbuff[j] == NULL) { if (netif_msg_ifup(ugeth)) @@ -2326,9 +2326,9 @@ static int ucc_geth_alloc_rx(struct ucc_geth_private *ugeth) /* Init Rx bds */ for (j = 0; j < ug_info->numQueuesRx; j++) { /* Setup the skbuff rings */ - ugeth->rx_skbuff[j] = kmalloc(sizeof(struct sk_buff *) * - ugeth->ug_info->bdRingLenRx[j], - GFP_KERNEL); + ugeth->rx_skbuff[j] = + kmalloc_array(ugeth->ug_info->bdRingLenRx[j], + sizeof(struct sk_buff *), GFP_KERNEL); if (ugeth->rx_skbuff[j] == NULL) { if (netif_msg_ifup(ugeth)) diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c index 85e1d14514fc..0ce07f6eb1e6 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c @@ -1406,8 +1406,8 @@ static int hns_dsaf_init(struct dsaf_device *dsaf_dev) return ret; /* malloc mem for tcam mac key(vlan+mac) */ - priv->soft_mac_tbl = vzalloc(sizeof(*priv->soft_mac_tbl) - * DSAF_TCAM_SUM); + priv->soft_mac_tbl = vzalloc(array_size(DSAF_TCAM_SUM, + sizeof(*priv->soft_mac_tbl))); if (!priv->soft_mac_tbl) { ret = -ENOMEM; goto remove_hw; diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c index 1ccb6443d2ed..ef9ef703d13a 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c @@ -2197,7 +2197,8 @@ static int hns_nic_init_ring_data(struct hns_nic_priv *priv) return -EINVAL; } - priv->ring_data = kzalloc(h->q_num * sizeof(*priv->ring_data) * 2, + priv->ring_data = kzalloc(array3_size(h->q_num, + sizeof(*priv->ring_data), 2), GFP_KERNEL); if (!priv->ring_data) return -ENOMEM; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index f2b31d278bc9..25a73bb2e642 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -2846,8 +2846,10 @@ static int hns3_get_ring_config(struct hns3_nic_priv *priv) struct pci_dev *pdev = h->pdev; int i, ret; - priv->ring_data = devm_kzalloc(&pdev->dev, h->kinfo.num_tqps * - sizeof(*priv->ring_data) * 2, + priv->ring_data = devm_kzalloc(&pdev->dev, + array3_size(h->kinfo.num_tqps, + sizeof(*priv->ring_data), + 2), GFP_KERNEL); if (!priv->ring_data) return -ENOMEM; diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_cmdq.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_cmdq.c index 28a81ac97af5..4d09ea786b35 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_hw_cmdq.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_cmdq.c @@ -753,11 +753,12 @@ static int init_cmdq(struct hinic_cmdq *cmdq, struct hinic_wq *wq, spin_lock_init(&cmdq->cmdq_lock); - cmdq->done = vzalloc(wq->q_depth * sizeof(*cmdq->done)); + cmdq->done = vzalloc(array_size(sizeof(*cmdq->done), wq->q_depth)); if (!cmdq->done) return -ENOMEM; - cmdq->errcode = vzalloc(wq->q_depth * sizeof(*cmdq->errcode)); + cmdq->errcode = vzalloc(array_size(sizeof(*cmdq->errcode), + wq->q_depth)); if (!cmdq->errcode) { err = -ENOMEM; goto err_errcode; diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c index c1b51edaaf62..525d8b89187b 100644 --- a/drivers/net/ethernet/ibm/ibmveth.c +++ b/drivers/net/ethernet/ibm/ibmveth.c @@ -171,7 +171,7 @@ static int ibmveth_alloc_buffer_pool(struct ibmveth_buff_pool *pool) { int i; - pool->free_map = kmalloc(sizeof(u16) * pool->size, GFP_KERNEL); + pool->free_map = kmalloc_array(pool->size, sizeof(u16), GFP_KERNEL); if (!pool->free_map) return -1; diff --git a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c index 5d365a986bb0..bdb3f8e65ed4 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c +++ b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c @@ -435,8 +435,8 @@ static int e1000_get_eeprom(struct net_device *netdev, first_word = eeprom->offset >> 1; last_word = (eeprom->offset + eeprom->len - 1) >> 1; - eeprom_buff = kmalloc(sizeof(u16) * - (last_word - first_word + 1), GFP_KERNEL); + eeprom_buff = kmalloc_array(last_word - first_word + 1, sizeof(u16), + GFP_KERNEL); if (!eeprom_buff) return -ENOMEM; diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c index e084cb734eb1..02ebf208f48b 100644 --- a/drivers/net/ethernet/intel/e1000e/ethtool.c +++ b/drivers/net/ethernet/intel/e1000e/ethtool.c @@ -509,8 +509,8 @@ static int e1000_get_eeprom(struct net_device *netdev, first_word = eeprom->offset >> 1; last_word = (eeprom->offset + eeprom->len - 1) >> 1; - eeprom_buff = kmalloc(sizeof(u16) * (last_word - first_word + 1), - GFP_KERNEL); + eeprom_buff = kmalloc_array(last_word - first_word + 1, sizeof(u16), + GFP_KERNEL); if (!eeprom_buff) return -ENOMEM; diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index acf1e8b52b8e..3ba0c90e7055 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -3312,7 +3312,7 @@ static int e1000e_write_mc_addr_list(struct net_device *netdev) return 0; } - mta_list = kzalloc(netdev_mc_count(netdev) * ETH_ALEN, GFP_ATOMIC); + mta_list = kcalloc(netdev_mc_count(netdev), ETH_ALEN, GFP_ATOMIC); if (!mta_list) return -ENOMEM; diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c b/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c index 7657daa27298..4895dd83dd08 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c @@ -558,7 +558,7 @@ static int fm10k_set_ringparam(struct net_device *netdev, /* allocate temporary buffer to store rings in */ i = max_t(int, interface->num_tx_queues, interface->num_rx_queues); - temp_ring = vmalloc(i * sizeof(struct fm10k_ring)); + temp_ring = vmalloc(array_size(i, sizeof(struct fm10k_ring))); if (!temp_ring) { err = -ENOMEM; diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c index 2d798499d35e..f92f7918112d 100644 --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c @@ -736,8 +736,8 @@ static int igb_get_eeprom(struct net_device *netdev, first_word = eeprom->offset >> 1; last_word = (eeprom->offset + eeprom->len - 1) >> 1; - eeprom_buff = kmalloc(sizeof(u16) * - (last_word - first_word + 1), GFP_KERNEL); + eeprom_buff = kmalloc_array(last_word - first_word + 1, sizeof(u16), + GFP_KERNEL); if (!eeprom_buff) return -ENOMEM; @@ -902,11 +902,11 @@ static int igb_set_ringparam(struct net_device *netdev, } if (adapter->num_tx_queues > adapter->num_rx_queues) - temp_ring = vmalloc(adapter->num_tx_queues * - sizeof(struct igb_ring)); + temp_ring = vmalloc(array_size(sizeof(struct igb_ring), + adapter->num_tx_queues)); else - temp_ring = vmalloc(adapter->num_rx_queues * - sizeof(struct igb_ring)); + temp_ring = vmalloc(array_size(sizeof(struct igb_ring), + adapter->num_rx_queues)); if (!temp_ring) { err = -ENOMEM; @@ -3245,8 +3245,8 @@ static int igb_get_module_eeprom(struct net_device *netdev, first_word = ee->offset >> 1; last_word = (ee->offset + ee->len - 1) >> 1; - dataword = kmalloc(sizeof(u16) * (last_word - first_word + 1), - GFP_KERNEL); + dataword = kmalloc_array(last_word - first_word + 1, sizeof(u16), + GFP_KERNEL); if (!dataword) return -ENOMEM; diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index c33821d2afb3..f707709969ac 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -3763,8 +3763,9 @@ static int igb_sw_init(struct igb_adapter *adapter) /* Assume MSI-X interrupts, will be checked during IRQ allocation */ adapter->flags |= IGB_FLAG_HAS_MSIX; - adapter->mac_table = kzalloc(sizeof(struct igb_mac_addr) * - hw->mac.rar_entry_count, GFP_ATOMIC); + adapter->mac_table = kcalloc(hw->mac.rar_entry_count, + sizeof(struct igb_mac_addr), + GFP_ATOMIC); if (!adapter->mac_table) return -ENOMEM; @@ -4752,7 +4753,7 @@ static int igb_write_mc_addr_list(struct net_device *netdev) return 0; } - mta_list = kzalloc(netdev_mc_count(netdev) * 6, GFP_ATOMIC); + mta_list = kcalloc(netdev_mc_count(netdev), 6, GFP_ATOMIC); if (!mta_list) return -ENOMEM; diff --git a/drivers/net/ethernet/intel/ixgb/ixgb_ethtool.c b/drivers/net/ethernet/intel/ixgb/ixgb_ethtool.c index 43744bf0fc1c..c8c93ac436d4 100644 --- a/drivers/net/ethernet/intel/ixgb/ixgb_ethtool.c +++ b/drivers/net/ethernet/intel/ixgb/ixgb_ethtool.c @@ -375,8 +375,9 @@ ixgb_get_eeprom(struct net_device *netdev, first_word = eeprom->offset >> 1; last_word = (eeprom->offset + eeprom->len - 1) >> 1; - eeprom_buff = kmalloc(sizeof(__le16) * - (last_word - first_word + 1), GFP_KERNEL); + eeprom_buff = kmalloc_array(last_word - first_word + 1, + sizeof(__le16), + GFP_KERNEL); if (!eeprom_buff) return -ENOMEM; diff --git a/drivers/net/ethernet/intel/ixgb/ixgb_main.c b/drivers/net/ethernet/intel/ixgb/ixgb_main.c index 62f2173bc20e..43664adf7a3c 100644 --- a/drivers/net/ethernet/intel/ixgb/ixgb_main.c +++ b/drivers/net/ethernet/intel/ixgb/ixgb_main.c @@ -1093,8 +1093,9 @@ ixgb_set_multi(struct net_device *netdev) rctl |= IXGB_RCTL_MPE; IXGB_WRITE_REG(hw, RCTL, rctl); } else { - u8 *mta = kmalloc(IXGB_MAX_NUM_MULTICAST_ADDRESSES * - ETH_ALEN, GFP_ATOMIC); + u8 *mta = kmalloc_array(ETH_ALEN, + IXGB_MAX_NUM_MULTICAST_ADDRESSES, + GFP_ATOMIC); u8 *addr; if (!mta) goto alloc_failed; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c index bdd179c29ea4..bd1ba88ec1d5 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c @@ -901,7 +901,7 @@ static int ixgbe_get_eeprom(struct net_device *netdev, last_word = (eeprom->offset + eeprom->len - 1) >> 1; eeprom_len = last_word - first_word + 1; - eeprom_buff = kmalloc(sizeof(u16) * eeprom_len, GFP_KERNEL); + eeprom_buff = kmalloc_array(eeprom_len, sizeof(u16), GFP_KERNEL); if (!eeprom_buff) return -ENOMEM; @@ -1063,7 +1063,7 @@ static int ixgbe_set_ringparam(struct net_device *netdev, /* allocate temporary buffer to store rings in */ i = max_t(int, adapter->num_tx_queues + adapter->num_xdp_queues, adapter->num_rx_queues); - temp_ring = vmalloc(i * sizeof(struct ixgbe_ring)); + temp_ring = vmalloc(array_size(i, sizeof(struct ixgbe_ring))); if (!temp_ring) { err = -ENOMEM; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 8d061af276d3..3e87dbbc9024 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -6034,8 +6034,8 @@ static int ixgbe_sw_init(struct ixgbe_adapter *adapter, for (i = 1; i < IXGBE_MAX_LINK_HANDLE; i++) adapter->jump_tables[i] = NULL; - adapter->mac_table = kzalloc(sizeof(struct ixgbe_mac_addr) * - hw->mac.num_rar_entries, + adapter->mac_table = kcalloc(hw->mac.num_rar_entries, + sizeof(struct ixgbe_mac_addr), GFP_ATOMIC); if (!adapter->mac_table) return -ENOMEM; diff --git a/drivers/net/ethernet/intel/ixgbevf/ethtool.c b/drivers/net/ethernet/intel/ixgbevf/ethtool.c index e7813d76527c..631c91046f39 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ethtool.c +++ b/drivers/net/ethernet/intel/ixgbevf/ethtool.c @@ -282,8 +282,9 @@ static int ixgbevf_set_ringparam(struct net_device *netdev, } if (new_tx_count != adapter->tx_ring_count) { - tx_ring = vmalloc((adapter->num_tx_queues + - adapter->num_xdp_queues) * sizeof(*tx_ring)); + tx_ring = vmalloc(array_size(sizeof(*tx_ring), + adapter->num_tx_queues + + adapter->num_xdp_queues)); if (!tx_ring) { err = -ENOMEM; goto clear_reset; @@ -327,7 +328,8 @@ static int ixgbevf_set_ringparam(struct net_device *netdev, } if (new_rx_count != adapter->rx_ring_count) { - rx_ring = vmalloc(adapter->num_rx_queues * sizeof(*rx_ring)); + rx_ring = vmalloc(array_size(sizeof(*rx_ring), + adapter->num_rx_queues)); if (!rx_ring) { err = -ENOMEM; goto clear_reset; diff --git a/drivers/net/ethernet/jme.c b/drivers/net/ethernet/jme.c index 8a165842fa85..06ff185eb188 100644 --- a/drivers/net/ethernet/jme.c +++ b/drivers/net/ethernet/jme.c @@ -589,8 +589,9 @@ jme_setup_tx_resources(struct jme_adapter *jme) atomic_set(&txring->next_to_clean, 0); atomic_set(&txring->nr_free, jme->tx_ring_size); - txring->bufinf = kzalloc(sizeof(struct jme_buffer_info) * - jme->tx_ring_size, GFP_ATOMIC); + txring->bufinf = kcalloc(jme->tx_ring_size, + sizeof(struct jme_buffer_info), + GFP_ATOMIC); if (unlikely(!(txring->bufinf))) goto err_free_txring; @@ -838,8 +839,9 @@ jme_setup_rx_resources(struct jme_adapter *jme) rxring->next_to_use = 0; atomic_set(&rxring->next_to_clean, 0); - rxring->bufinf = kzalloc(sizeof(struct jme_buffer_info) * - jme->rx_ring_size, GFP_ATOMIC); + rxring->bufinf = kcalloc(jme->rx_ring_size, + sizeof(struct jme_buffer_info), + GFP_ATOMIC); if (unlikely(!(rxring->bufinf))) goto err_free_rxring; diff --git a/drivers/net/ethernet/mellanox/mlx4/alloc.c b/drivers/net/ethernet/mellanox/mlx4/alloc.c index 6dabd983e7e0..4bdf25059542 100644 --- a/drivers/net/ethernet/mellanox/mlx4/alloc.c +++ b/drivers/net/ethernet/mellanox/mlx4/alloc.c @@ -185,8 +185,8 @@ int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask, bitmap->avail = num - reserved_top - reserved_bot; bitmap->effective_len = bitmap->avail; spin_lock_init(&bitmap->lock); - bitmap->table = kzalloc(BITS_TO_LONGS(bitmap->max) * - sizeof(long), GFP_KERNEL); + bitmap->table = kcalloc(BITS_TO_LONGS(bitmap->max), sizeof(long), + GFP_KERNEL); if (!bitmap->table) return -ENOMEM; diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index 6a9086dc1e92..e65bc3c95630 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c @@ -2377,20 +2377,23 @@ int mlx4_multi_func_init(struct mlx4_dev *dev) struct mlx4_vf_admin_state *vf_admin; priv->mfunc.master.slave_state = - kzalloc(dev->num_slaves * - sizeof(struct mlx4_slave_state), GFP_KERNEL); + kcalloc(dev->num_slaves, + sizeof(struct mlx4_slave_state), + GFP_KERNEL); if (!priv->mfunc.master.slave_state) goto err_comm; priv->mfunc.master.vf_admin = - kzalloc(dev->num_slaves * - sizeof(struct mlx4_vf_admin_state), GFP_KERNEL); + kcalloc(dev->num_slaves, + sizeof(struct mlx4_vf_admin_state), + GFP_KERNEL); if (!priv->mfunc.master.vf_admin) goto err_comm_admin; priv->mfunc.master.vf_oper = - kzalloc(dev->num_slaves * - sizeof(struct mlx4_vf_oper_state), GFP_KERNEL); + kcalloc(dev->num_slaves, + sizeof(struct mlx4_vf_oper_state), + GFP_KERNEL); if (!priv->mfunc.master.vf_oper) goto err_comm_oper; @@ -2636,9 +2639,9 @@ int mlx4_cmd_use_events(struct mlx4_dev *dev) int i; int err = 0; - priv->cmd.context = kmalloc(priv->cmd.max_cmds * - sizeof(struct mlx4_cmd_context), - GFP_KERNEL); + priv->cmd.context = kmalloc_array(priv->cmd.max_cmds, + sizeof(struct mlx4_cmd_context), + GFP_KERNEL); if (!priv->cmd.context) return -ENOMEM; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 9670b33fc9b1..65eb06e017e4 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -2229,13 +2229,15 @@ static int mlx4_en_copy_priv(struct mlx4_en_priv *dst, if (!dst->tx_ring_num[t]) continue; - dst->tx_ring[t] = kzalloc(sizeof(struct mlx4_en_tx_ring *) * - MAX_TX_RINGS, GFP_KERNEL); + dst->tx_ring[t] = kcalloc(MAX_TX_RINGS, + sizeof(struct mlx4_en_tx_ring *), + GFP_KERNEL); if (!dst->tx_ring[t]) goto err_free_tx; - dst->tx_cq[t] = kzalloc(sizeof(struct mlx4_en_cq *) * - MAX_TX_RINGS, GFP_KERNEL); + dst->tx_cq[t] = kcalloc(MAX_TX_RINGS, + sizeof(struct mlx4_en_cq *), + GFP_KERNEL); if (!dst->tx_cq[t]) { kfree(dst->tx_ring[t]); goto err_free_tx; @@ -3320,14 +3322,16 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, if (!priv->tx_ring_num[t]) continue; - priv->tx_ring[t] = kzalloc(sizeof(struct mlx4_en_tx_ring *) * - MAX_TX_RINGS, GFP_KERNEL); + priv->tx_ring[t] = kcalloc(MAX_TX_RINGS, + sizeof(struct mlx4_en_tx_ring *), + GFP_KERNEL); if (!priv->tx_ring[t]) { err = -ENOMEM; goto out; } - priv->tx_cq[t] = kzalloc(sizeof(struct mlx4_en_cq *) * - MAX_TX_RINGS, GFP_KERNEL); + priv->tx_cq[t] = kcalloc(MAX_TX_RINGS, + sizeof(struct mlx4_en_cq *), + GFP_KERNEL); if (!priv->tx_cq[t]) { err = -ENOMEM; goto out; diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c index 6f57c052053e..1f3372c1802e 100644 --- a/drivers/net/ethernet/mellanox/mlx4/eq.c +++ b/drivers/net/ethernet/mellanox/mlx4/eq.c @@ -1211,8 +1211,9 @@ int mlx4_init_eq_table(struct mlx4_dev *dev) } priv->eq_table.irq_names = - kmalloc(MLX4_IRQNAME_SIZE * (dev->caps.num_comp_vectors + 1), - GFP_KERNEL); + kmalloc_array(MLX4_IRQNAME_SIZE, + (dev->caps.num_comp_vectors + 1), + GFP_KERNEL); if (!priv->eq_table.irq_names) { err = -ENOMEM; goto err_out_clr_int; diff --git a/drivers/net/ethernet/mellanox/mlx4/icm.c b/drivers/net/ethernet/mellanox/mlx4/icm.c index 5342bd8a3d0b..7262c6310650 100644 --- a/drivers/net/ethernet/mellanox/mlx4/icm.c +++ b/drivers/net/ethernet/mellanox/mlx4/icm.c @@ -408,7 +408,7 @@ int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table, return -EINVAL; num_icm = (nobj + obj_per_chunk - 1) / obj_per_chunk; - table->icm = kvzalloc(num_icm * sizeof(*table->icm), GFP_KERNEL); + table->icm = kvcalloc(num_icm, sizeof(*table->icm), GFP_KERNEL); if (!table->icm) return -ENOMEM; table->virt = virt; diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 0a30d81aab3b..872014702fc1 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -2982,7 +2982,8 @@ static int mlx4_init_steering(struct mlx4_dev *dev) int num_entries = dev->caps.num_ports; int i, j; - priv->steer = kzalloc(sizeof(struct mlx4_steer) * num_entries, GFP_KERNEL); + priv->steer = kcalloc(num_entries, sizeof(struct mlx4_steer), + GFP_KERNEL); if (!priv->steer) return -ENOMEM; @@ -3103,7 +3104,7 @@ static u64 mlx4_enable_sriov(struct mlx4_dev *dev, struct pci_dev *pdev, } } - dev->dev_vfs = kzalloc(total_vfs * sizeof(*dev->dev_vfs), GFP_KERNEL); + dev->dev_vfs = kcalloc(total_vfs, sizeof(*dev->dev_vfs), GFP_KERNEL); if (NULL == dev->dev_vfs) { mlx4_err(dev, "Failed to allocate memory for VFs\n"); goto disable_sriov; diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index 29e50f787349..7b1b5ac986d0 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -487,7 +487,7 @@ int mlx4_init_resource_tracker(struct mlx4_dev *dev) int max_vfs_guarantee_counter = get_max_gauranteed_vfs_counter(dev); priv->mfunc.master.res_tracker.slave_list = - kzalloc(dev->num_slaves * sizeof(struct slave_list), + kcalloc(dev->num_slaves, sizeof(struct slave_list), GFP_KERNEL); if (!priv->mfunc.master.res_tracker.slave_list) return -ENOMEM; @@ -507,19 +507,21 @@ int mlx4_init_resource_tracker(struct mlx4_dev *dev) for (i = 0; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) { struct resource_allocator *res_alloc = &priv->mfunc.master.res_tracker.res_alloc[i]; - res_alloc->quota = kmalloc((dev->persist->num_vfs + 1) * - sizeof(int), GFP_KERNEL); - res_alloc->guaranteed = kmalloc((dev->persist->num_vfs + 1) * - sizeof(int), GFP_KERNEL); + res_alloc->quota = kmalloc_array(dev->persist->num_vfs + 1, + sizeof(int), + GFP_KERNEL); + res_alloc->guaranteed = kmalloc_array(dev->persist->num_vfs + 1, + sizeof(int), + GFP_KERNEL); if (i == RES_MAC || i == RES_VLAN) - res_alloc->allocated = kzalloc(MLX4_MAX_PORTS * - (dev->persist->num_vfs - + 1) * - sizeof(int), GFP_KERNEL); + res_alloc->allocated = + kcalloc(MLX4_MAX_PORTS * + (dev->persist->num_vfs + 1), + sizeof(int), GFP_KERNEL); else - res_alloc->allocated = kzalloc((dev->persist-> - num_vfs + 1) * - sizeof(int), GFP_KERNEL); + res_alloc->allocated = + kcalloc(dev->persist->num_vfs + 1, + sizeof(int), GFP_KERNEL); /* Reduce the sink counter */ if (i == RES_COUNTER) res_alloc->res_free = dev->caps.max_counters - 1; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 89c96a0f708e..56c1b6f5593e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -352,7 +352,7 @@ static int mlx5e_rq_alloc_mpwqe_info(struct mlx5e_rq *rq, { int wq_sz = mlx5_wq_ll_get_size(&rq->mpwqe.wq); - rq->mpwqe.info = kzalloc_node(wq_sz * sizeof(*rq->mpwqe.info), + rq->mpwqe.info = kcalloc_node(wq_sz, sizeof(*rq->mpwqe.info), GFP_KERNEL, cpu_to_node(c->cpu)); if (!rq->mpwqe.info) return -ENOMEM; @@ -448,7 +448,7 @@ static int mlx5e_init_di_list(struct mlx5e_rq *rq, { int len = wq_sz << rq->wqe.info.log_num_frags; - rq->wqe.di = kvzalloc_node(len * sizeof(*rq->wqe.di), + rq->wqe.di = kvzalloc_node(array_size(len, sizeof(*rq->wqe.di)), GFP_KERNEL, cpu_to_node(cpu)); if (!rq->wqe.di) return -ENOMEM; @@ -563,8 +563,8 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c, rq->wqe.info = rqp->frags_info; rq->wqe.frags = - kvzalloc_node((wq_sz << rq->wqe.info.log_num_frags) * - sizeof(*rq->wqe.frags), + kvzalloc_node(array_size(sizeof(*rq->wqe.frags), + (wq_sz << rq->wqe.info.log_num_frags)), GFP_KERNEL, cpu_to_node(c->cpu)); if (!rq->wqe.frags) { err = -ENOMEM; @@ -972,7 +972,7 @@ static int mlx5e_alloc_xdpsq_db(struct mlx5e_xdpsq *sq, int numa) { int wq_sz = mlx5_wq_cyc_get_size(&sq->wq); - sq->db.di = kzalloc_node(sizeof(*sq->db.di) * wq_sz, + sq->db.di = kcalloc_node(wq_sz, sizeof(*sq->db.di), GFP_KERNEL, numa); if (!sq->db.di) { mlx5e_free_xdpsq_db(sq); @@ -1031,7 +1031,7 @@ static int mlx5e_alloc_icosq_db(struct mlx5e_icosq *sq, int numa) { u8 wq_sz = mlx5_wq_cyc_get_size(&sq->wq); - sq->db.ico_wqe = kzalloc_node(sizeof(*sq->db.ico_wqe) * wq_sz, + sq->db.ico_wqe = kcalloc_node(wq_sz, sizeof(*sq->db.ico_wqe), GFP_KERNEL, numa); if (!sq->db.ico_wqe) return -ENOMEM; @@ -1086,9 +1086,9 @@ static int mlx5e_alloc_txqsq_db(struct mlx5e_txqsq *sq, int numa) int wq_sz = mlx5_wq_cyc_get_size(&sq->wq); int df_sz = wq_sz * MLX5_SEND_WQEBB_NUM_DS; - sq->db.dma_fifo = kzalloc_node(df_sz * sizeof(*sq->db.dma_fifo), + sq->db.dma_fifo = kcalloc_node(df_sz, sizeof(*sq->db.dma_fifo), GFP_KERNEL, numa); - sq->db.wqe_info = kzalloc_node(wq_sz * sizeof(*sq->db.wqe_info), + sq->db.wqe_info = kcalloc_node(wq_sz, sizeof(*sq->db.wqe_info), GFP_KERNEL, numa); if (!sq->db.dma_fifo || !sq->db.wqe_info) { mlx5e_free_txqsq_db(sq); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/conn.c b/drivers/net/ethernet/mellanox/mlx5/core/fpga/conn.c index 4138a770ed57..8ca1d1949d93 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/conn.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/conn.c @@ -549,15 +549,17 @@ static int mlx5_fpga_conn_create_qp(struct mlx5_fpga_conn *conn, if (err) goto out; - conn->qp.rq.bufs = kvzalloc(sizeof(conn->qp.rq.bufs[0]) * - conn->qp.rq.size, GFP_KERNEL); + conn->qp.rq.bufs = kvcalloc(conn->qp.rq.size, + sizeof(conn->qp.rq.bufs[0]), + GFP_KERNEL); if (!conn->qp.rq.bufs) { err = -ENOMEM; goto err_wq; } - conn->qp.sq.bufs = kvzalloc(sizeof(conn->qp.sq.bufs[0]) * - conn->qp.sq.size, GFP_KERNEL); + conn->qp.sq.bufs = kvcalloc(conn->qp.sq.size, + sizeof(conn->qp.sq.bufs[0]), + GFP_KERNEL); if (!conn->qp.sq.bufs) { err = -ENOMEM; goto err_rq_bufs; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c b/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c index a0433b48e833..5645a4facad2 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c @@ -381,7 +381,7 @@ int mlx5_fpga_ipsec_counters_read(struct mlx5_core_dev *mdev, u64 *counters, count = mlx5_fpga_ipsec_counters_count(mdev); - data = kzalloc(sizeof(*data) * count * 2, GFP_KERNEL); + data = kzalloc(array3_size(sizeof(*data), count, 2), GFP_KERNEL); if (!data) { ret = -ENOMEM; goto out; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c index 857035583ccd..1e062e6b2587 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c @@ -394,8 +394,9 @@ static int mlx5_init_pin_config(struct mlx5_clock *clock) int i; clock->ptp_info.pin_config = - kzalloc(sizeof(*clock->ptp_info.pin_config) * - clock->ptp_info.n_pins, GFP_KERNEL); + kcalloc(clock->ptp_info.n_pins, + sizeof(*clock->ptp_info.pin_config), + GFP_KERNEL); if (!clock->ptp_info.pin_config) return -ENOMEM; clock->ptp_info.enable = mlx5_ptp_enable; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c index 91262b0573e3..cad603c35271 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c @@ -740,7 +740,8 @@ int mlxsw_sp_tc_qdisc_init(struct mlxsw_sp_port *mlxsw_sp_port) mlxsw_sp_port->root_qdisc->prio_bitmap = 0xff; mlxsw_sp_port->root_qdisc->tclass_num = MLXSW_SP_PORT_DEFAULT_TCLASS; - mlxsw_sp_qdisc = kzalloc(sizeof(*mlxsw_sp_qdisc) * IEEE_8021QAZ_MAX_TCS, + mlxsw_sp_qdisc = kcalloc(IEEE_8021QAZ_MAX_TCS, + sizeof(*mlxsw_sp_qdisc), GFP_KERNEL); if (!mlxsw_sp_qdisc) goto err_tclass_qdiscs_init; diff --git a/drivers/net/ethernet/micrel/ksz884x.c b/drivers/net/ethernet/micrel/ksz884x.c index 52207508744c..b72d1bd11296 100644 --- a/drivers/net/ethernet/micrel/ksz884x.c +++ b/drivers/net/ethernet/micrel/ksz884x.c @@ -4372,7 +4372,7 @@ static void ksz_update_timer(struct ksz_timer_info *info) */ static int ksz_alloc_soft_desc(struct ksz_desc_info *desc_info, int transmit) { - desc_info->ring = kzalloc(sizeof(struct ksz_desc) * desc_info->alloc, + desc_info->ring = kcalloc(desc_info->alloc, sizeof(struct ksz_desc), GFP_KERNEL); if (!desc_info->ring) return 1; diff --git a/drivers/net/ethernet/moxa/moxart_ether.c b/drivers/net/ethernet/moxa/moxart_ether.c index 2e4effa9fe45..b34055ac476f 100644 --- a/drivers/net/ethernet/moxa/moxart_ether.c +++ b/drivers/net/ethernet/moxa/moxart_ether.c @@ -507,15 +507,15 @@ static int moxart_mac_probe(struct platform_device *pdev) goto init_fail; } - priv->tx_buf_base = kmalloc(priv->tx_buf_size * TX_DESC_NUM, - GFP_ATOMIC); + priv->tx_buf_base = kmalloc_array(priv->tx_buf_size, TX_DESC_NUM, + GFP_ATOMIC); if (!priv->tx_buf_base) { ret = -ENOMEM; goto init_fail; } - priv->rx_buf_base = kmalloc(priv->rx_buf_size * RX_DESC_NUM, - GFP_ATOMIC); + priv->rx_buf_base = kmalloc_array(priv->rx_buf_size, RX_DESC_NUM, + GFP_ATOMIC); if (!priv->rx_buf_base) { ret = -ENOMEM; goto init_fail; diff --git a/drivers/net/ethernet/neterion/vxge/vxge-config.c b/drivers/net/ethernet/neterion/vxge/vxge-config.c index c60da9e8bf14..358ed6118881 100644 --- a/drivers/net/ethernet/neterion/vxge/vxge-config.c +++ b/drivers/net/ethernet/neterion/vxge/vxge-config.c @@ -2220,22 +2220,22 @@ __vxge_hw_channel_allocate(struct __vxge_hw_vpath_handle *vph, channel->length = length; channel->vp_id = vp_id; - channel->work_arr = kzalloc(sizeof(void *)*length, GFP_KERNEL); + channel->work_arr = kcalloc(length, sizeof(void *), GFP_KERNEL); if (channel->work_arr == NULL) goto exit1; - channel->free_arr = kzalloc(sizeof(void *)*length, GFP_KERNEL); + channel->free_arr = kcalloc(length, sizeof(void *), GFP_KERNEL); if (channel->free_arr == NULL) goto exit1; channel->free_ptr = length; - channel->reserve_arr = kzalloc(sizeof(void *)*length, GFP_KERNEL); + channel->reserve_arr = kcalloc(length, sizeof(void *), GFP_KERNEL); if (channel->reserve_arr == NULL) goto exit1; channel->reserve_ptr = length; channel->reserve_top = 0; - channel->orig_arr = kzalloc(sizeof(void *)*length, GFP_KERNEL); + channel->orig_arr = kcalloc(length, sizeof(void *), GFP_KERNEL); if (channel->orig_arr == NULL) goto exit1; @@ -2565,7 +2565,7 @@ __vxge_hw_mempool_grow(struct vxge_hw_mempool *mempool, u32 num_allocate, * allocate new memblock and its private part at once. * This helps to minimize memory usage a lot. */ mempool->memblocks_priv_arr[i] = - vzalloc(mempool->items_priv_size * n_items); + vzalloc(array_size(mempool->items_priv_size, n_items)); if (mempool->memblocks_priv_arr[i] == NULL) { status = VXGE_HW_ERR_OUT_OF_MEMORY; goto exit; @@ -2665,7 +2665,7 @@ __vxge_hw_mempool_create(struct __vxge_hw_device *devh, /* allocate array of memblocks */ mempool->memblocks_arr = - vzalloc(sizeof(void *) * mempool->memblocks_max); + vzalloc(array_size(sizeof(void *), mempool->memblocks_max)); if (mempool->memblocks_arr == NULL) { __vxge_hw_mempool_destroy(mempool); status = VXGE_HW_ERR_OUT_OF_MEMORY; @@ -2675,7 +2675,7 @@ __vxge_hw_mempool_create(struct __vxge_hw_device *devh, /* allocate array of private parts of items per memblocks */ mempool->memblocks_priv_arr = - vzalloc(sizeof(void *) * mempool->memblocks_max); + vzalloc(array_size(sizeof(void *), mempool->memblocks_max)); if (mempool->memblocks_priv_arr == NULL) { __vxge_hw_mempool_destroy(mempool); status = VXGE_HW_ERR_OUT_OF_MEMORY; @@ -2685,8 +2685,8 @@ __vxge_hw_mempool_create(struct __vxge_hw_device *devh, /* allocate array of memblocks DMA objects */ mempool->memblocks_dma_arr = - vzalloc(sizeof(struct vxge_hw_mempool_dma) * - mempool->memblocks_max); + vzalloc(array_size(sizeof(struct vxge_hw_mempool_dma), + mempool->memblocks_max)); if (mempool->memblocks_dma_arr == NULL) { __vxge_hw_mempool_destroy(mempool); status = VXGE_HW_ERR_OUT_OF_MEMORY; @@ -2695,7 +2695,8 @@ __vxge_hw_mempool_create(struct __vxge_hw_device *devh, } /* allocate hash array of items */ - mempool->items_arr = vzalloc(sizeof(void *) * mempool->items_max); + mempool->items_arr = vzalloc(array_size(sizeof(void *), + mempool->items_max)); if (mempool->items_arr == NULL) { __vxge_hw_mempool_destroy(mempool); status = VXGE_HW_ERR_OUT_OF_MEMORY; diff --git a/drivers/net/ethernet/neterion/vxge/vxge-main.c b/drivers/net/ethernet/neterion/vxge/vxge-main.c index a8918bb7c802..5ae3fa82909f 100644 --- a/drivers/net/ethernet/neterion/vxge/vxge-main.c +++ b/drivers/net/ethernet/neterion/vxge/vxge-main.c @@ -3429,8 +3429,8 @@ static int vxge_device_register(struct __vxge_hw_device *hldev, vxge_initialize_ethtool_ops(ndev); /* Allocate memory for vpath */ - vdev->vpaths = kzalloc((sizeof(struct vxge_vpath)) * - no_of_vpath, GFP_KERNEL); + vdev->vpaths = kcalloc(no_of_vpath, sizeof(struct vxge_vpath), + GFP_KERNEL); if (!vdev->vpaths) { vxge_debug_init(VXGE_ERR, "%s: vpath memory allocation failed", diff --git a/drivers/net/ethernet/netronome/nfp/abm/main.c b/drivers/net/ethernet/netronome/nfp/abm/main.c index 1561c2724c26..b84a6c2d387b 100644 --- a/drivers/net/ethernet/netronome/nfp/abm/main.c +++ b/drivers/net/ethernet/netronome/nfp/abm/main.c @@ -590,7 +590,7 @@ nfp_abm_vnic_alloc(struct nfp_app *app, struct nfp_net *nn, unsigned int id) alink->id = id; alink->parent = TC_H_ROOT; alink->total_queues = alink->vnic->max_rx_rings; - alink->qdiscs = kvzalloc(sizeof(*alink->qdiscs) * alink->total_queues, + alink->qdiscs = kvcalloc(alink->total_queues, sizeof(*alink->qdiscs), GFP_KERNEL); if (!alink->qdiscs) { err = -ENOMEM; diff --git a/drivers/net/ethernet/netronome/nfp/flower/metadata.c b/drivers/net/ethernet/netronome/nfp/flower/metadata.c index 21668aa435e8..93fb809f50d1 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/metadata.c +++ b/drivers/net/ethernet/netronome/nfp/flower/metadata.c @@ -417,7 +417,8 @@ int nfp_flower_metadata_init(struct nfp_app *app) /* Init ring buffer and unallocated stats_ids. */ priv->stats_ids.free_list.buf = - vmalloc(NFP_FL_STATS_ENTRY_RS * NFP_FL_STATS_ELEM_RS); + vmalloc(array_size(NFP_FL_STATS_ELEM_RS, + NFP_FL_STATS_ENTRY_RS)); if (!priv->stats_ids.free_list.buf) goto err_free_last_used; diff --git a/drivers/net/ethernet/ni/nixge.c b/drivers/net/ethernet/ni/nixge.c index b092894dd128..09f674ec0f9e 100644 --- a/drivers/net/ethernet/ni/nixge.c +++ b/drivers/net/ethernet/ni/nixge.c @@ -247,9 +247,8 @@ static int nixge_hw_dma_bd_init(struct net_device *ndev) if (!priv->tx_bd_v) goto out; - priv->tx_skb = devm_kzalloc(ndev->dev.parent, - sizeof(*priv->tx_skb) * - TX_BD_NUM, + priv->tx_skb = devm_kcalloc(ndev->dev.parent, + TX_BD_NUM, sizeof(*priv->tx_skb), GFP_KERNEL); if (!priv->tx_skb) goto out; diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c index 66c665d0b926..7cbd0174459c 100644 --- a/drivers/net/ethernet/nvidia/forcedeth.c +++ b/drivers/net/ethernet/nvidia/forcedeth.c @@ -4630,8 +4630,10 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri ring->tx_pending), &ring_addr, GFP_ATOMIC); } - rx_skbuff = kmalloc(sizeof(struct nv_skb_map) * ring->rx_pending, GFP_KERNEL); - tx_skbuff = kmalloc(sizeof(struct nv_skb_map) * ring->tx_pending, GFP_KERNEL); + rx_skbuff = kmalloc_array(ring->rx_pending, sizeof(struct nv_skb_map), + GFP_KERNEL); + tx_skbuff = kmalloc_array(ring->tx_pending, sizeof(struct nv_skb_map), + GFP_KERNEL); if (!rxtx_ring || !rx_skbuff || !tx_skbuff) { /* fall back to old rings */ if (!nv_optimized(np)) { diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c index 7cd494611a74..34a1581eda95 100644 --- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c +++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c @@ -2178,7 +2178,7 @@ static void pch_gbe_set_multi(struct net_device *netdev) if (mc_count >= PCH_GBE_MAR_ENTRIES) return; - mta_list = kmalloc(mc_count * ETH_ALEN, GFP_ATOMIC); + mta_list = kmalloc_array(ETH_ALEN, mc_count, GFP_ATOMIC); if (!mta_list) return; diff --git a/drivers/net/ethernet/pasemi/pasemi_mac.c b/drivers/net/ethernet/pasemi/pasemi_mac.c index 07a2eb3781b1..8a31a02c9f47 100644 --- a/drivers/net/ethernet/pasemi/pasemi_mac.c +++ b/drivers/net/ethernet/pasemi/pasemi_mac.c @@ -390,8 +390,9 @@ static int pasemi_mac_setup_rx_resources(const struct net_device *dev) spin_lock_init(&ring->lock); ring->size = RX_RING_SIZE; - ring->ring_info = kzalloc(sizeof(struct pasemi_mac_buffer) * - RX_RING_SIZE, GFP_KERNEL); + ring->ring_info = kcalloc(RX_RING_SIZE, + sizeof(struct pasemi_mac_buffer), + GFP_KERNEL); if (!ring->ring_info) goto out_ring_info; @@ -473,8 +474,9 @@ pasemi_mac_setup_tx_resources(const struct net_device *dev) spin_lock_init(&ring->lock); ring->size = TX_RING_SIZE; - ring->ring_info = kzalloc(sizeof(struct pasemi_mac_buffer) * - TX_RING_SIZE, GFP_KERNEL); + ring->ring_info = kcalloc(TX_RING_SIZE, + sizeof(struct pasemi_mac_buffer), + GFP_KERNEL); if (!ring->ring_info) goto out_ring_info; diff --git a/drivers/net/ethernet/qlogic/qed/qed_debug.c b/drivers/net/ethernet/qlogic/qed/qed_debug.c index b9ec460dd996..a14e48489029 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_debug.c +++ b/drivers/net/ethernet/qlogic/qed/qed_debug.c @@ -6617,7 +6617,8 @@ static enum dbg_status qed_mcp_trace_alloc_meta(struct qed_hwfn *p_hwfn, /* Read no. of modules and allocate memory for their pointers */ meta->modules_num = qed_read_byte_from_buf(meta_buf_bytes, &offset); - meta->modules = kzalloc(meta->modules_num * sizeof(char *), GFP_KERNEL); + meta->modules = kcalloc(meta->modules_num, sizeof(char *), + GFP_KERNEL); if (!meta->modules) return DBG_STATUS_VIRT_MEM_ALLOC_FAILED; @@ -6645,7 +6646,7 @@ static enum dbg_status qed_mcp_trace_alloc_meta(struct qed_hwfn *p_hwfn, /* Read number of formats and allocate memory for all formats */ meta->formats_num = qed_read_dword_from_buf(meta_buf_bytes, &offset); - meta->formats = kzalloc(meta->formats_num * + meta->formats = kcalloc(meta->formats_num, sizeof(struct mcp_trace_format), GFP_KERNEL); if (!meta->formats) diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index b285edc8d6a1..329781cda77f 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -814,26 +814,26 @@ static int qed_alloc_qm_data(struct qed_hwfn *p_hwfn) if (rc) goto alloc_err; - qm_info->qm_pq_params = kzalloc(sizeof(*qm_info->qm_pq_params) * - qed_init_qm_get_num_pqs(p_hwfn), + qm_info->qm_pq_params = kcalloc(qed_init_qm_get_num_pqs(p_hwfn), + sizeof(*qm_info->qm_pq_params), GFP_KERNEL); if (!qm_info->qm_pq_params) goto alloc_err; - qm_info->qm_vport_params = kzalloc(sizeof(*qm_info->qm_vport_params) * - qed_init_qm_get_num_vports(p_hwfn), + qm_info->qm_vport_params = kcalloc(qed_init_qm_get_num_vports(p_hwfn), + sizeof(*qm_info->qm_vport_params), GFP_KERNEL); if (!qm_info->qm_vport_params) goto alloc_err; - qm_info->qm_port_params = kzalloc(sizeof(*qm_info->qm_port_params) * - p_hwfn->cdev->num_ports_in_engine, + qm_info->qm_port_params = kcalloc(p_hwfn->cdev->num_ports_in_engine, + sizeof(*qm_info->qm_port_params), GFP_KERNEL); if (!qm_info->qm_port_params) goto alloc_err; - qm_info->wfq_data = kzalloc(sizeof(*qm_info->wfq_data) * - qed_init_qm_get_num_vports(p_hwfn), + qm_info->wfq_data = kcalloc(qed_init_qm_get_num_vports(p_hwfn), + sizeof(*qm_info->wfq_data), GFP_KERNEL); if (!qm_info->wfq_data) goto alloc_err; diff --git a/drivers/net/ethernet/qlogic/qed/qed_init_ops.c b/drivers/net/ethernet/qlogic/qed/qed_init_ops.c index 3bb76da6baa2..d9ab5add27a8 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_init_ops.c +++ b/drivers/net/ethernet/qlogic/qed/qed_init_ops.c @@ -149,12 +149,12 @@ int qed_init_alloc(struct qed_hwfn *p_hwfn) if (IS_VF(p_hwfn->cdev)) return 0; - rt_data->b_valid = kzalloc(sizeof(bool) * RUNTIME_ARRAY_SIZE, + rt_data->b_valid = kcalloc(RUNTIME_ARRAY_SIZE, sizeof(bool), GFP_KERNEL); if (!rt_data->b_valid) return -ENOMEM; - rt_data->init_val = kzalloc(sizeof(u32) * RUNTIME_ARRAY_SIZE, + rt_data->init_val = kcalloc(RUNTIME_ARRAY_SIZE, sizeof(u32), GFP_KERNEL); if (!rt_data->init_val) { kfree(rt_data->b_valid); diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.c b/drivers/net/ethernet/qlogic/qed/qed_l2.c index 1f6ac848109d..99973e10b179 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_l2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_l2.c @@ -98,7 +98,7 @@ int qed_l2_alloc(struct qed_hwfn *p_hwfn) p_l2_info->queues = max_t(u8, rx, tx); } - pp_qids = kzalloc(sizeof(unsigned long *) * p_l2_info->queues, + pp_qids = kcalloc(p_l2_info->queues, sizeof(unsigned long *), GFP_KERNEL); if (!pp_qids) return -ENOMEM; @@ -2435,7 +2435,7 @@ static int qed_update_vport(struct qed_dev *cdev, if (!cdev) return -ENODEV; - rss = vzalloc(sizeof(*rss) * cdev->num_hwfns); + rss = vzalloc(array_size(sizeof(*rss), cdev->num_hwfns)); if (!rss) return -ENOMEM; diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.c b/drivers/net/ethernet/qlogic/qed/qed_mcp.c index 6f9927d1a501..4e0b443c9519 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_mcp.c +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.c @@ -2578,9 +2578,9 @@ int qed_mcp_nvm_info_populate(struct qed_hwfn *p_hwfn) goto err0; } - nvm_info->image_att = kmalloc(nvm_info->num_images * - sizeof(struct bist_nvm_image_att), - GFP_KERNEL); + nvm_info->image_att = kmalloc_array(nvm_info->num_images, + sizeof(struct bist_nvm_image_att), + GFP_KERNEL); if (!nvm_info->image_att) { rc = -ENOMEM; goto err0; diff --git a/drivers/net/ethernet/qlogic/qede/qede_filter.c b/drivers/net/ethernet/qlogic/qede/qede_filter.c index e9e088d9c815..b823bfe2ea4d 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_filter.c +++ b/drivers/net/ethernet/qlogic/qede/qede_filter.c @@ -342,8 +342,9 @@ int qede_alloc_arfs(struct qede_dev *edev) for (i = 0; i <= QEDE_RFS_FLW_MASK; i++) INIT_HLIST_HEAD(QEDE_ARFS_BUCKET_HEAD(edev, i)); - edev->arfs->arfs_fltr_bmap = vzalloc(BITS_TO_LONGS(QEDE_RFS_MAX_FLTR) * - sizeof(long)); + edev->arfs->arfs_fltr_bmap = + vzalloc(array_size(sizeof(long), + BITS_TO_LONGS(QEDE_RFS_MAX_FLTR))); if (!edev->arfs->arfs_fltr_bmap) { vfree(edev->arfs); edev->arfs = NULL; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index 97c146e7698a..569d54ededec 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c @@ -386,8 +386,9 @@ int qlcnic_83xx_setup_intr(struct qlcnic_adapter *adapter) } /* setup interrupt mapping table for fw */ - ahw->intr_tbl = vzalloc(num_msix * - sizeof(struct qlcnic_intrpt_config)); + ahw->intr_tbl = + vzalloc(array_size(num_msix, + sizeof(struct qlcnic_intrpt_config))); if (!ahw->intr_tbl) return -ENOMEM; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index 1b5f7d57b6f8..2d38d1ac2aae 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -916,8 +916,9 @@ int qlcnic_82xx_mq_intrpt(struct qlcnic_adapter *adapter, int op_type) if (qlcnic_check_multi_tx(adapter) && !ahw->diag_test && (adapter->flags & QLCNIC_MSIX_ENABLED)) { - ahw->intr_tbl = vzalloc(ahw->num_msix * - sizeof(struct qlcnic_intrpt_config)); + ahw->intr_tbl = + vzalloc(array_size(sizeof(struct qlcnic_intrpt_config), + ahw->num_msix)); if (!ahw->intr_tbl) return -ENOMEM; @@ -1025,15 +1026,17 @@ int qlcnic_init_pci_info(struct qlcnic_adapter *adapter) act_pci_func = ahw->total_nic_func; - adapter->npars = kzalloc(sizeof(struct qlcnic_npar_info) * - act_pci_func, GFP_KERNEL); + adapter->npars = kcalloc(act_pci_func, + sizeof(struct qlcnic_npar_info), + GFP_KERNEL); if (!adapter->npars) { ret = -ENOMEM; goto err_pci_info; } - adapter->eswitch = kzalloc(sizeof(struct qlcnic_eswitch) * - QLCNIC_NIU_MAX_XG_PORTS, GFP_KERNEL); + adapter->eswitch = kcalloc(QLCNIC_NIU_MAX_XG_PORTS, + sizeof(struct qlcnic_eswitch), + GFP_KERNEL); if (!adapter->eswitch) { ret = -ENOMEM; goto err_npars; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c index c58180f40844..0c744b9c6e0a 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c @@ -157,8 +157,8 @@ int qlcnic_sriov_init(struct qlcnic_adapter *adapter, int num_vfs) adapter->ahw->sriov = sriov; sriov->num_vfs = num_vfs; bc = &sriov->bc; - sriov->vf_info = kzalloc(sizeof(struct qlcnic_vf_info) * - num_vfs, GFP_KERNEL); + sriov->vf_info = kcalloc(num_vfs, sizeof(struct qlcnic_vf_info), + GFP_KERNEL); if (!sriov->vf_info) { err = -ENOMEM; goto qlcnic_free_sriov; @@ -450,7 +450,7 @@ static int qlcnic_sriov_set_guest_vlan_mode(struct qlcnic_adapter *adapter, return 0; num_vlans = sriov->num_allowed_vlans; - sriov->allowed_vlans = kzalloc(sizeof(u16) * num_vlans, GFP_KERNEL); + sriov->allowed_vlans = kcalloc(num_vlans, sizeof(u16), GFP_KERNEL); if (!sriov->allowed_vlans) return -ENOMEM; @@ -706,7 +706,7 @@ static inline int qlcnic_sriov_alloc_bc_trans(struct qlcnic_bc_trans **trans) static inline int qlcnic_sriov_alloc_bc_msg(struct qlcnic_bc_hdr **hdr, u32 size) { - *hdr = kzalloc(sizeof(struct qlcnic_bc_hdr) * size, GFP_ATOMIC); + *hdr = kcalloc(size, sizeof(struct qlcnic_bc_hdr), GFP_ATOMIC); if (!*hdr) return -ENOMEM; diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_main.c b/drivers/net/ethernet/qlogic/qlge/qlge_main.c index 70de062b72a1..353f1c129af1 100644 --- a/drivers/net/ethernet/qlogic/qlge/qlge_main.c +++ b/drivers/net/ethernet/qlogic/qlge/qlge_main.c @@ -2810,7 +2810,8 @@ static int ql_alloc_tx_resources(struct ql_adapter *qdev, goto pci_alloc_err; tx_ring->q = - kmalloc(tx_ring->wq_len * sizeof(struct tx_ring_desc), GFP_KERNEL); + kmalloc_array(tx_ring->wq_len, sizeof(struct tx_ring_desc), + GFP_KERNEL); if (tx_ring->q == NULL) goto err; diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index d90a7b1f4088..23f0785c0573 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -4984,7 +4984,8 @@ static int efx_ef10_filter_table_probe(struct efx_nic *efx) net_dev->hw_features &= ~NETIF_F_HW_VLAN_CTAG_FILTER; } - table->entry = vzalloc(HUNT_FILTER_TBL_ROWS * sizeof(*table->entry)); + table->entry = vzalloc(array_size(HUNT_FILTER_TBL_ROWS, + sizeof(*table->entry))); if (!table->entry) { rc = -ENOMEM; goto fail; diff --git a/drivers/net/ethernet/sfc/falcon/farch.c b/drivers/net/ethernet/sfc/falcon/farch.c index 494884f6af4a..411a2f419447 100644 --- a/drivers/net/ethernet/sfc/falcon/farch.c +++ b/drivers/net/ethernet/sfc/falcon/farch.c @@ -2755,7 +2755,8 @@ int ef4_farch_filter_table_probe(struct ef4_nic *efx) GFP_KERNEL); if (!table->used_bitmap) goto fail; - table->spec = vzalloc(table->size * sizeof(*table->spec)); + table->spec = vzalloc(array_size(sizeof(*table->spec), + table->size)); if (!table->spec) goto fail; } diff --git a/drivers/net/ethernet/sfc/farch.c b/drivers/net/ethernet/sfc/farch.c index c72adf8b52ea..8edf20967c82 100644 --- a/drivers/net/ethernet/sfc/farch.c +++ b/drivers/net/ethernet/sfc/farch.c @@ -2826,7 +2826,8 @@ int efx_farch_filter_table_probe(struct efx_nic *efx) GFP_KERNEL); if (!table->used_bitmap) goto fail; - table->spec = vzalloc(table->size * sizeof(*table->spec)); + table->spec = vzalloc(array_size(sizeof(*table->spec), + table->size)); if (!table->spec) goto fail; } diff --git a/drivers/net/ethernet/socionext/netsec.c b/drivers/net/ethernet/socionext/netsec.c index ce8071fc90c4..e080d3e7c582 100644 --- a/drivers/net/ethernet/socionext/netsec.c +++ b/drivers/net/ethernet/socionext/netsec.c @@ -973,7 +973,7 @@ static int netsec_alloc_dring(struct netsec_priv *priv, enum ring_id id) goto err; } - dring->desc = kzalloc(DESC_NUM * sizeof(*dring->desc), GFP_KERNEL); + dring->desc = kcalloc(DESC_NUM, sizeof(*dring->desc), GFP_KERNEL); if (!dring->desc) { ret = -ENOMEM; goto err; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c index 881c94b73e2f..2258cd8cc844 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c @@ -277,8 +277,8 @@ static int tc_init(struct stmmac_priv *priv) /* Reserve one last filter which lets all pass */ priv->tc_entries_max = count; - priv->tc_entries = devm_kzalloc(priv->device, - sizeof(*priv->tc_entries) * count, GFP_KERNEL); + priv->tc_entries = devm_kcalloc(priv->device, + count, sizeof(*priv->tc_entries), GFP_KERNEL); if (!priv->tc_entries) return -ENOMEM; diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 534596ce00d3..358edab9e72e 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -2740,8 +2740,9 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data, } data->active_slave = prop; - data->slave_data = devm_kzalloc(&pdev->dev, data->slaves - * sizeof(struct cpsw_slave_data), + data->slave_data = devm_kcalloc(&pdev->dev, + data->slaves, + sizeof(struct cpsw_slave_data), GFP_KERNEL); if (!data->slave_data) return -ENOMEM; @@ -3045,8 +3046,8 @@ static int cpsw_probe(struct platform_device *pdev) memcpy(ndev->dev_addr, priv->mac_addr, ETH_ALEN); - cpsw->slaves = devm_kzalloc(&pdev->dev, - sizeof(struct cpsw_slave) * data->slaves, + cpsw->slaves = devm_kcalloc(&pdev->dev, + data->slaves, sizeof(struct cpsw_slave), GFP_KERNEL); if (!cpsw->slaves) { ret = -ENOMEM; diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c index 6e455a27a8de..72b98e27c992 100644 --- a/drivers/net/ethernet/ti/netcp_ethss.c +++ b/drivers/net/ethernet/ti/netcp_ethss.c @@ -3285,8 +3285,8 @@ static int set_xgbe_ethss10_priv(struct gbe_priv *gbe_dev, gbe_dev->et_stats = xgbe10_et_stats; gbe_dev->num_et_stats = ARRAY_SIZE(xgbe10_et_stats); - gbe_dev->hw_stats = devm_kzalloc(gbe_dev->dev, - gbe_dev->num_et_stats * sizeof(u64), + gbe_dev->hw_stats = devm_kcalloc(gbe_dev->dev, + gbe_dev->num_et_stats, sizeof(u64), GFP_KERNEL); if (!gbe_dev->hw_stats) { dev_err(gbe_dev->dev, "hw_stats memory allocation failed\n"); @@ -3294,8 +3294,8 @@ static int set_xgbe_ethss10_priv(struct gbe_priv *gbe_dev, } gbe_dev->hw_stats_prev = - devm_kzalloc(gbe_dev->dev, - gbe_dev->num_et_stats * sizeof(u32), + devm_kcalloc(gbe_dev->dev, + gbe_dev->num_et_stats, sizeof(u32), GFP_KERNEL); if (!gbe_dev->hw_stats_prev) { dev_err(gbe_dev->dev, @@ -3405,8 +3405,8 @@ static int set_gbe_ethss14_priv(struct gbe_priv *gbe_dev, gbe_dev->et_stats = gbe13_et_stats; gbe_dev->num_et_stats = ARRAY_SIZE(gbe13_et_stats); - gbe_dev->hw_stats = devm_kzalloc(gbe_dev->dev, - gbe_dev->num_et_stats * sizeof(u64), + gbe_dev->hw_stats = devm_kcalloc(gbe_dev->dev, + gbe_dev->num_et_stats, sizeof(u64), GFP_KERNEL); if (!gbe_dev->hw_stats) { dev_err(gbe_dev->dev, "hw_stats memory allocation failed\n"); @@ -3414,8 +3414,8 @@ static int set_gbe_ethss14_priv(struct gbe_priv *gbe_dev, } gbe_dev->hw_stats_prev = - devm_kzalloc(gbe_dev->dev, - gbe_dev->num_et_stats * sizeof(u32), + devm_kcalloc(gbe_dev->dev, + gbe_dev->num_et_stats, sizeof(u32), GFP_KERNEL); if (!gbe_dev->hw_stats_prev) { dev_err(gbe_dev->dev, @@ -3477,8 +3477,8 @@ static int set_gbenu_ethss_priv(struct gbe_priv *gbe_dev, gbe_dev->num_et_stats = GBENU_ET_STATS_HOST_SIZE + GBENU_ET_STATS_PORT_SIZE; - gbe_dev->hw_stats = devm_kzalloc(gbe_dev->dev, - gbe_dev->num_et_stats * sizeof(u64), + gbe_dev->hw_stats = devm_kcalloc(gbe_dev->dev, + gbe_dev->num_et_stats, sizeof(u64), GFP_KERNEL); if (!gbe_dev->hw_stats) { dev_err(gbe_dev->dev, "hw_stats memory allocation failed\n"); @@ -3486,8 +3486,8 @@ static int set_gbenu_ethss_priv(struct gbe_priv *gbe_dev, } gbe_dev->hw_stats_prev = - devm_kzalloc(gbe_dev->dev, - gbe_dev->num_et_stats * sizeof(u32), + devm_kcalloc(gbe_dev->dev, + gbe_dev->num_et_stats, sizeof(u32), GFP_KERNEL); if (!gbe_dev->hw_stats_prev) { dev_err(gbe_dev->dev, diff --git a/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c b/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c index eed18f88bdff..302079e22b06 100644 --- a/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c +++ b/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c @@ -2320,8 +2320,9 @@ static struct net_device *gelic_wl_alloc(struct gelic_card *card) pr_debug("%s: wl=%p port=%p\n", __func__, wl, port); /* allocate scan list */ - wl->networks = kzalloc(sizeof(struct gelic_wl_scan_info) * - GELIC_WL_BSS_MAX_ENT, GFP_KERNEL); + wl->networks = kcalloc(GELIC_WL_BSS_MAX_ENT, + sizeof(struct gelic_wl_scan_info), + GFP_KERNEL); if (!wl->networks) goto fail_bss; diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c index f38e32a7ec9c..ec629a730005 100644 --- a/drivers/net/gtp.c +++ b/drivers/net/gtp.c @@ -742,11 +742,13 @@ static int gtp_hashtable_new(struct gtp_dev *gtp, int hsize) { int i; - gtp->addr_hash = kmalloc(sizeof(struct hlist_head) * hsize, GFP_KERNEL); + gtp->addr_hash = kmalloc_array(hsize, sizeof(struct hlist_head), + GFP_KERNEL); if (gtp->addr_hash == NULL) return -ENOMEM; - gtp->tid_hash = kmalloc(sizeof(struct hlist_head) * hsize, GFP_KERNEL); + gtp->tid_hash = kmalloc_array(hsize, sizeof(struct hlist_head), + GFP_KERNEL); if (gtp->tid_hash == NULL) goto err1; diff --git a/drivers/net/hippi/rrunner.c b/drivers/net/hippi/rrunner.c index f41116488079..029206e4da3b 100644 --- a/drivers/net/hippi/rrunner.c +++ b/drivers/net/hippi/rrunner.c @@ -1583,7 +1583,7 @@ static int rr_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return -EPERM; } - image = kmalloc(EEPROM_WORDS * sizeof(u32), GFP_KERNEL); + image = kmalloc_array(EEPROM_WORDS, sizeof(u32), GFP_KERNEL); if (!image) return -ENOMEM; diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c index a6c87793d899..79e9b103188b 100644 --- a/drivers/net/phy/dp83640.c +++ b/drivers/net/phy/dp83640.c @@ -1097,8 +1097,9 @@ static struct dp83640_clock *dp83640_clock_get_bus(struct mii_bus *bus) if (!clock) goto out; - clock->caps.pin_config = kzalloc(sizeof(struct ptp_pin_desc) * - DP83640_N_PINS, GFP_KERNEL); + clock->caps.pin_config = kcalloc(DP83640_N_PINS, + sizeof(struct ptp_pin_desc), + GFP_KERNEL); if (!clock->caps.pin_config) { kfree(clock); clock = NULL; diff --git a/drivers/net/phy/phy_led_triggers.c b/drivers/net/phy/phy_led_triggers.c index 39ecad25b201..491efc1bf5c4 100644 --- a/drivers/net/phy/phy_led_triggers.c +++ b/drivers/net/phy/phy_led_triggers.c @@ -128,9 +128,9 @@ int phy_led_triggers_register(struct phy_device *phy) if (err) goto out_free_link; - phy->phy_led_triggers = devm_kzalloc(&phy->mdio.dev, - sizeof(struct phy_led_trigger) * - phy->phy_num_led_triggers, + phy->phy_led_triggers = devm_kcalloc(&phy->mdio.dev, + phy->phy_num_led_triggers, + sizeof(struct phy_led_trigger), GFP_KERNEL); if (!phy->phy_led_triggers) { err = -ENOMEM; diff --git a/drivers/net/ppp/bsd_comp.c b/drivers/net/ppp/bsd_comp.c index a9b759add187..61fedb23d3cf 100644 --- a/drivers/net/ppp/bsd_comp.c +++ b/drivers/net/ppp/bsd_comp.c @@ -406,7 +406,7 @@ static void *bsd_alloc (unsigned char *options, int opt_len, int decomp) * Allocate space for the dictionary. This may be more than one page in * length. */ - db->dict = vmalloc(hsize * sizeof(struct bsd_dict)); + db->dict = vmalloc(array_size(hsize, sizeof(struct bsd_dict))); if (!db->dict) { bsd_free (db); @@ -425,7 +425,7 @@ static void *bsd_alloc (unsigned char *options, int opt_len, int decomp) */ else { - db->lens = vmalloc((maxmaxcode + 1) * sizeof(db->lens[0])); + db->lens = vmalloc(array_size(sizeof(db->lens[0]), (maxmaxcode + 1))); if (!db->lens) { bsd_free (db); diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c index 157b67c1bf8e..67ffe74747a1 100644 --- a/drivers/net/ppp/pptp.c +++ b/drivers/net/ppp/pptp.c @@ -648,7 +648,7 @@ static int __init pptp_init_module(void) int err = 0; pr_info("PPTP driver version " PPTP_DRIVER_VERSION "\n"); - callid_sock = vzalloc((MAX_CALLID + 1) * sizeof(void *)); + callid_sock = vzalloc(array_size(sizeof(void *), (MAX_CALLID + 1))); if (!callid_sock) return -ENOMEM; diff --git a/drivers/net/slip/slip.c b/drivers/net/slip/slip.c index 8940417c30e5..b008266e91ea 100644 --- a/drivers/net/slip/slip.c +++ b/drivers/net/slip/slip.c @@ -1307,7 +1307,7 @@ static int __init slip_init(void) printk(KERN_INFO "SLIP linefill/keepalive option.\n"); #endif - slip_devs = kzalloc(sizeof(struct net_device *)*slip_maxdev, + slip_devs = kcalloc(slip_maxdev, sizeof(struct net_device *), GFP_KERNEL); if (!slip_devs) return -ENOMEM; diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 8863fa023500..b070959737ff 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -280,7 +280,7 @@ static int __team_options_register(struct team *team, struct team_option **dst_opts; int err; - dst_opts = kzalloc(sizeof(struct team_option *) * option_count, + dst_opts = kcalloc(option_count, sizeof(struct team_option *), GFP_KERNEL); if (!dst_opts) return -ENOMEM; @@ -791,7 +791,8 @@ static int team_queue_override_init(struct team *team) if (!queue_cnt) return 0; - listarr = kmalloc(sizeof(struct list_head) * queue_cnt, GFP_KERNEL); + listarr = kmalloc_array(queue_cnt, sizeof(struct list_head), + GFP_KERNEL); if (!listarr) return -ENOMEM; team->qom_lists = listarr; diff --git a/drivers/net/usb/asix_common.c b/drivers/net/usb/asix_common.c index f4d7362eb325..e95dd12edec4 100644 --- a/drivers/net/usb/asix_common.c +++ b/drivers/net/usb/asix_common.c @@ -640,8 +640,8 @@ int asix_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, first_word = eeprom->offset >> 1; last_word = (eeprom->offset + eeprom->len - 1) >> 1; - eeprom_buff = kmalloc(sizeof(u16) * (last_word - first_word + 1), - GFP_KERNEL); + eeprom_buff = kmalloc_array(last_word - first_word + 1, sizeof(u16), + GFP_KERNEL); if (!eeprom_buff) return -ENOMEM; @@ -680,8 +680,8 @@ int asix_set_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, first_word = eeprom->offset >> 1; last_word = (eeprom->offset + eeprom->len - 1) >> 1; - eeprom_buff = kmalloc(sizeof(u16) * (last_word - first_word + 1), - GFP_KERNEL); + eeprom_buff = kmalloc_array(last_word - first_word + 1, sizeof(u16), + GFP_KERNEL); if (!eeprom_buff) return -ENOMEM; diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c index a6ef75907ae9..9e8ad372f419 100644 --- a/drivers/net/usb/ax88179_178a.c +++ b/drivers/net/usb/ax88179_178a.c @@ -599,8 +599,8 @@ ax88179_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, first_word = eeprom->offset >> 1; last_word = (eeprom->offset + eeprom->len - 1) >> 1; - eeprom_buff = kmalloc(sizeof(u16) * (last_word - first_word + 1), - GFP_KERNEL); + eeprom_buff = kmalloc_array(last_word - first_word + 1, sizeof(u16), + GFP_KERNEL); if (!eeprom_buff) return -ENOMEM; diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index 309b88acd3d0..06b4d290784d 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -1661,7 +1661,7 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message) } if (pdata->wolopts & (WAKE_BCAST | WAKE_MCAST | WAKE_ARP | WAKE_UCAST)) { - u32 *filter_mask = kzalloc(sizeof(u32) * 32, GFP_KERNEL); + u32 *filter_mask = kcalloc(32, sizeof(u32), GFP_KERNEL); u32 command[2]; u32 offset[2]; u32 crc[4]; diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index d9eea8cfe6cb..770aa624147f 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1323,8 +1323,8 @@ static int build_dma_sg(const struct sk_buff *skb, struct urb *urb) return 0; /* reserve one for zero packet */ - urb->sg = kmalloc((num_sgs + 1) * sizeof(struct scatterlist), - GFP_ATOMIC); + urb->sg = kmalloc_array(num_sgs + 1, sizeof(struct scatterlist), + GFP_ATOMIC); if (!urb->sg) return -ENOMEM; diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 1619ee3070b6..b6c9a2af3732 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -2552,17 +2552,17 @@ static int virtnet_find_vqs(struct virtnet_info *vi) virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ); /* Allocate space for find_vqs parameters */ - vqs = kzalloc(total_vqs * sizeof(*vqs), GFP_KERNEL); + vqs = kcalloc(total_vqs, sizeof(*vqs), GFP_KERNEL); if (!vqs) goto err_vq; - callbacks = kmalloc(total_vqs * sizeof(*callbacks), GFP_KERNEL); + callbacks = kmalloc_array(total_vqs, sizeof(*callbacks), GFP_KERNEL); if (!callbacks) goto err_callback; - names = kmalloc(total_vqs * sizeof(*names), GFP_KERNEL); + names = kmalloc_array(total_vqs, sizeof(*names), GFP_KERNEL); if (!names) goto err_names; if (!vi->big_packets || vi->mergeable_rx_bufs) { - ctx = kzalloc(total_vqs * sizeof(*ctx), GFP_KERNEL); + ctx = kcalloc(total_vqs, sizeof(*ctx), GFP_KERNEL); if (!ctx) goto err_ctx; } else { @@ -2626,10 +2626,10 @@ static int virtnet_alloc_queues(struct virtnet_info *vi) vi->ctrl = kzalloc(sizeof(*vi->ctrl), GFP_KERNEL); if (!vi->ctrl) goto err_ctrl; - vi->sq = kzalloc(sizeof(*vi->sq) * vi->max_queue_pairs, GFP_KERNEL); + vi->sq = kcalloc(vi->max_queue_pairs, sizeof(*vi->sq), GFP_KERNEL); if (!vi->sq) goto err_sq; - vi->rq = kzalloc(sizeof(*vi->rq) * vi->max_queue_pairs, GFP_KERNEL); + vi->rq = kcalloc(vi->max_queue_pairs, sizeof(*vi->rq), GFP_KERNEL); if (!vi->rq) goto err_rq; diff --git a/drivers/net/wan/fsl_ucc_hdlc.c b/drivers/net/wan/fsl_ucc_hdlc.c index 4205dfd19da3..9b09c9d0d0fb 100644 --- a/drivers/net/wan/fsl_ucc_hdlc.c +++ b/drivers/net/wan/fsl_ucc_hdlc.c @@ -198,12 +198,14 @@ static int uhdlc_init(struct ucc_hdlc_private *priv) goto free_tx_bd; } - priv->rx_skbuff = kzalloc(priv->rx_ring_size * sizeof(*priv->rx_skbuff), + priv->rx_skbuff = kcalloc(priv->rx_ring_size, + sizeof(*priv->rx_skbuff), GFP_KERNEL); if (!priv->rx_skbuff) goto free_ucc_pram; - priv->tx_skbuff = kzalloc(priv->tx_ring_size * sizeof(*priv->tx_skbuff), + priv->tx_skbuff = kcalloc(priv->tx_ring_size, + sizeof(*priv->tx_skbuff), GFP_KERNEL); if (!priv->tx_skbuff) goto free_rx_skbuff; diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index bd23f6940488..c72d8af122a2 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -582,7 +582,7 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt) } htt->rx_ring.netbufs_ring = - kzalloc(htt->rx_ring.size * sizeof(struct sk_buff *), + kcalloc(htt->rx_ring.size, sizeof(struct sk_buff *), GFP_KERNEL); if (!htt->rx_ring.netbufs_ring) goto err_netbuf; diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 2e34a1fc5ba6..8c49a26fc571 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -155,7 +155,7 @@ ath10k_wmi_tlv_parse_alloc(struct ath10k *ar, const void *ptr, const void **tb; int ret; - tb = kzalloc(sizeof(*tb) * WMI_TLV_TAG_MAX, gfp); + tb = kcalloc(WMI_TLV_TAG_MAX, sizeof(*tb), gfp); if (!tb) return ERR_PTR(-ENOMEM); diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index 3513bbec4639..e01faf641288 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -931,7 +931,7 @@ static int open_file_eeprom(struct inode *inode, struct file *file) /* Create buffer and read in eeprom */ - buf = vmalloc(eesize * 2); + buf = vmalloc(array_size(eesize, 2)); if (!buf) { ret = -ENOMEM; goto err; diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 641b13a279e1..b1b8bc326830 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -890,7 +890,8 @@ ath5k_hw_rfregs_init(struct ath5k_hw *ah, * ah->ah_rf_banks based on ah->ah_rf_banks_size * we set above */ if (ah->ah_rf_banks == NULL) { - ah->ah_rf_banks = kmalloc(sizeof(u32) * ah->ah_rf_banks_size, + ah->ah_rf_banks = kmalloc_array(ah->ah_rf_banks_size, + sizeof(u32), GFP_KERNEL); if (ah->ah_rf_banks == NULL) { ATH5K_ERR(ah, "out of memory\n"); diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 2ba8cf3f38af..0687697d5e2d 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -1041,7 +1041,7 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, n_channels = request->n_channels; - channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL); + channels = kcalloc(n_channels, sizeof(u16), GFP_KERNEL); if (channels == NULL) { ath6kl_warn("failed to set scan channels, scan all channels"); n_channels = 0; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c index 6343cc91953e..34e100940284 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c @@ -925,7 +925,7 @@ int ar9003_paprd_create_curve(struct ath_hw *ah, memset(caldata->pa_table[chain], 0, sizeof(caldata->pa_table[chain])); - buf = kmalloc(2 * 48 * sizeof(u32), GFP_KERNEL); + buf = kmalloc_array(2 * 48, sizeof(u32), GFP_KERNEL); if (!buf) return -ENOMEM; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 6b37036b2d36..e60bea4604e4 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -127,13 +127,13 @@ void ath9k_hw_read_array(struct ath_hw *ah, u32 array[][2], int size) u32 *tmp_reg_list, *tmp_data; int i; - tmp_reg_list = kmalloc(size * sizeof(u32), GFP_KERNEL); + tmp_reg_list = kmalloc_array(size, sizeof(u32), GFP_KERNEL); if (!tmp_reg_list) { dev_err(ah->dev, "%s: tmp_reg_list: alloc filed\n", __func__); return; } - tmp_data = kmalloc(size * sizeof(u32), GFP_KERNEL); + tmp_data = kmalloc_array(size, sizeof(u32), GFP_KERNEL); if (!tmp_data) { dev_err(ah->dev, "%s tmp_data: alloc filed\n", __func__); goto error_tmp_data; diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 29e93c953d93..7f1bdea742b8 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -1958,7 +1958,7 @@ static int carl9170_parse_eeprom(struct ar9170 *ar) if (!bands) return -EINVAL; - ar->survey = kzalloc(sizeof(struct survey_info) * chans, GFP_KERNEL); + ar->survey = kcalloc(chans, sizeof(struct survey_info), GFP_KERNEL); if (!ar->survey) return -ENOMEM; ar->num_channels = chans; @@ -1988,8 +1988,9 @@ int carl9170_register(struct ar9170 *ar) if (WARN_ON(ar->mem_bitmap)) return -EINVAL; - ar->mem_bitmap = kzalloc(roundup(ar->fw.mem_blocks, BITS_PER_LONG) * - sizeof(unsigned long), GFP_KERNEL); + ar->mem_bitmap = kcalloc(roundup(ar->fw.mem_blocks, BITS_PER_LONG), + sizeof(unsigned long), + GFP_KERNEL); if (!ar->mem_bitmap) return -ENOMEM; diff --git a/drivers/net/wireless/broadcom/b43/phy_n.c b/drivers/net/wireless/broadcom/b43/phy_n.c index f2a2f41e3c96..44ab080d6518 100644 --- a/drivers/net/wireless/broadcom/b43/phy_n.c +++ b/drivers/net/wireless/broadcom/b43/phy_n.c @@ -1518,7 +1518,7 @@ static int b43_nphy_load_samples(struct b43_wldev *dev, u16 i; u32 *data; - data = kzalloc(len * sizeof(u32), GFP_KERNEL); + data = kcalloc(len, sizeof(u32), GFP_KERNEL); if (!data) { b43err(dev->wl, "allocation for samples loading failed\n"); return -ENOMEM; diff --git a/drivers/net/wireless/broadcom/b43legacy/main.c b/drivers/net/wireless/broadcom/b43legacy/main.c index f1e3dad57629..55f411925960 100644 --- a/drivers/net/wireless/broadcom/b43legacy/main.c +++ b/drivers/net/wireless/broadcom/b43legacy/main.c @@ -3300,8 +3300,8 @@ static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev) if ((phy->type == B43legacy_PHYTYPE_B) || (phy->type == B43legacy_PHYTYPE_G)) { - phy->_lo_pairs = kzalloc(sizeof(struct b43legacy_lopair) - * B43legacy_LO_COUNT, + phy->_lo_pairs = kcalloc(B43legacy_LO_COUNT, + sizeof(struct b43legacy_lopair), GFP_KERNEL); if (!phy->_lo_pairs) return -ENOMEM; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c index 49d37ad96958..c40ba8855cd5 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c @@ -1486,8 +1486,9 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr) (struct brcmf_commonring **)if_msgbuf->commonrings; msgbuf->flowrings = (struct brcmf_commonring **)if_msgbuf->flowrings; msgbuf->max_flowrings = if_msgbuf->max_flowrings; - msgbuf->flowring_dma_handle = kzalloc(msgbuf->max_flowrings * - sizeof(*msgbuf->flowring_dma_handle), GFP_KERNEL); + msgbuf->flowring_dma_handle = + kcalloc(msgbuf->max_flowrings, + sizeof(*msgbuf->flowring_dma_handle), GFP_KERNEL); if (!msgbuf->flowring_dma_handle) goto fail; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c index 4b2149b48362..3e9c4f2f5dd1 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c @@ -1058,7 +1058,7 @@ static s32 brcmf_p2p_act_frm_search(struct brcmf_p2p_info *p2p, u16 channel) channel_cnt = AF_PEER_SEARCH_CNT; else channel_cnt = SOCIAL_CHAN_CNT; - default_chan_list = kzalloc(channel_cnt * sizeof(*default_chan_list), + default_chan_list = kcalloc(channel_cnt, sizeof(*default_chan_list), GFP_KERNEL); if (default_chan_list == NULL) { brcmf_err("channel list allocation failed\n"); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c index 0a14942b8216..7d4e8f589fdc 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c @@ -507,7 +507,7 @@ brcms_c_attach_malloc(uint unit, uint *err, uint devid) wlc->hw->wlc = wlc; wlc->hw->bandstate[0] = - kzalloc(sizeof(struct brcms_hw_band) * MAXBANDS, GFP_ATOMIC); + kcalloc(MAXBANDS, sizeof(struct brcms_hw_band), GFP_ATOMIC); if (wlc->hw->bandstate[0] == NULL) { *err = 1006; goto fail; @@ -521,7 +521,8 @@ brcms_c_attach_malloc(uint unit, uint *err, uint devid) } wlc->modulecb = - kzalloc(sizeof(struct modulecb) * BRCMS_MAXMODULES, GFP_ATOMIC); + kcalloc(BRCMS_MAXMODULES, sizeof(struct modulecb), + GFP_ATOMIC); if (wlc->modulecb == NULL) { *err = 1009; goto fail; @@ -553,7 +554,7 @@ brcms_c_attach_malloc(uint unit, uint *err, uint devid) } wlc->bandstate[0] = - kzalloc(sizeof(struct brcms_band)*MAXBANDS, GFP_ATOMIC); + kcalloc(MAXBANDS, sizeof(struct brcms_band), GFP_ATOMIC); if (wlc->bandstate[0] == NULL) { *err = 1025; goto fail; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c index 9d830d27b229..9fb0d9fbd939 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c @@ -1387,7 +1387,7 @@ wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi, s16 *ptr; struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; - ptr = kmalloc(sizeof(s16) * 131, GFP_ATOMIC); + ptr = kmalloc_array(131, sizeof(s16), GFP_ATOMIC); if (NULL == ptr) return false; if (module == 2) { @@ -2670,7 +2670,7 @@ wlc_lcnphy_tx_iqlo_cal(struct brcms_phy *pi, u16 *values_to_save; struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; - values_to_save = kmalloc(sizeof(u16) * 20, GFP_ATOMIC); + values_to_save = kmalloc_array(20, sizeof(u16), GFP_ATOMIC); if (NULL == values_to_save) return; @@ -3678,11 +3678,11 @@ wlc_lcnphy_a1(struct brcms_phy *pi, int cal_type, int num_levels, u16 *phy_c32; phy_c21 = 0; phy_c10 = phy_c13 = phy_c14 = phy_c8 = 0; - ptr = kmalloc(sizeof(s16) * 131, GFP_ATOMIC); + ptr = kmalloc_array(131, sizeof(s16), GFP_ATOMIC); if (NULL == ptr) return; - phy_c32 = kmalloc(sizeof(u16) * 20, GFP_ATOMIC); + phy_c32 = kmalloc_array(20, sizeof(u16), GFP_ATOMIC); if (NULL == phy_c32) { kfree(ptr); return; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c index 7e01981bc5c8..1a187557982e 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c @@ -23032,7 +23032,7 @@ wlc_phy_loadsampletable_nphy(struct brcms_phy *pi, struct cordic_iq *tone_buf, u16 t; u32 *data_buf = NULL; - data_buf = kmalloc(sizeof(u32) * num_samps, GFP_ATOMIC); + data_buf = kmalloc_array(num_samps, sizeof(u32), GFP_ATOMIC); if (data_buf == NULL) return; @@ -23074,7 +23074,8 @@ wlc_phy_gen_load_samples_nphy(struct brcms_phy *pi, u32 f_kHz, u16 max_val, tbl_len = (phy_bw << 1); } - tone_buf = kmalloc(sizeof(struct cordic_iq) * tbl_len, GFP_ATOMIC); + tone_buf = kmalloc_array(tbl_len, sizeof(struct cordic_iq), + GFP_ATOMIC); if (tone_buf == NULL) return 0; diff --git a/drivers/net/wireless/cisco/airo.c b/drivers/net/wireless/cisco/airo.c index ce0fbf83285f..72046e182745 100644 --- a/drivers/net/wireless/cisco/airo.c +++ b/drivers/net/wireless/cisco/airo.c @@ -7127,7 +7127,7 @@ static int airo_get_aplist(struct net_device *dev, int i; int loseSync = capable(CAP_NET_ADMIN) ? 1: -1; - qual = kmalloc(IW_MAX_AP * sizeof(*qual), GFP_KERNEL); + qual = kmalloc_array(IW_MAX_AP, sizeof(*qual), GFP_KERNEL); if (!qual) return -ENOMEM; diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.c b/drivers/net/wireless/intel/ipw2x00/ipw2100.c index 7c4f550a1475..b8fd3cc90634 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2100.c @@ -3445,8 +3445,9 @@ static int ipw2100_msg_allocate(struct ipw2100_priv *priv) dma_addr_t p; priv->msg_buffers = - kmalloc(IPW_COMMAND_POOL_SIZE * sizeof(struct ipw2100_tx_packet), - GFP_KERNEL); + kmalloc_array(IPW_COMMAND_POOL_SIZE, + sizeof(struct ipw2100_tx_packet), + GFP_KERNEL); if (!priv->msg_buffers) return -ENOMEM; @@ -4587,9 +4588,9 @@ static int ipw2100_rx_allocate(struct ipw2100_priv *priv) /* * allocate packets */ - priv->rx_buffers = kmalloc(RX_QUEUE_LENGTH * - sizeof(struct ipw2100_rx_packet), - GFP_KERNEL); + priv->rx_buffers = kmalloc_array(RX_QUEUE_LENGTH, + sizeof(struct ipw2100_rx_packet), + GFP_KERNEL); if (!priv->rx_buffers) { IPW_DEBUG_INFO("can't allocate rx packet buffer table\n"); diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c index f26beeb6c5ff..8a858f7e36f4 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c @@ -3208,13 +3208,13 @@ static int ipw_load_firmware(struct ipw_priv *priv, u8 * data, size_t len) IPW_DEBUG_TRACE("<< :\n"); - virts = kmalloc(sizeof(void *) * CB_NUMBER_OF_ELEMENTS_SMALL, - GFP_KERNEL); + virts = kmalloc_array(CB_NUMBER_OF_ELEMENTS_SMALL, sizeof(void *), + GFP_KERNEL); if (!virts) return -ENOMEM; - phys = kmalloc(sizeof(dma_addr_t) * CB_NUMBER_OF_ELEMENTS_SMALL, - GFP_KERNEL); + phys = kmalloc_array(CB_NUMBER_OF_ELEMENTS_SMALL, sizeof(dma_addr_t), + GFP_KERNEL); if (!phys) { kfree(virts); return -ENOMEM; @@ -3782,7 +3782,7 @@ static int ipw_queue_tx_init(struct ipw_priv *priv, { struct pci_dev *dev = priv->pci_dev; - q->txb = kmalloc(sizeof(q->txb[0]) * count, GFP_KERNEL); + q->txb = kmalloc_array(count, sizeof(q->txb[0]), GFP_KERNEL); if (!q->txb) { IPW_ERROR("vmalloc for auxiliary BD structures failed\n"); return -ENOMEM; diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c index 063e19ced7c8..6514baf799fe 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.c +++ b/drivers/net/wireless/intel/iwlegacy/common.c @@ -922,7 +922,7 @@ il_init_channel_map(struct il_priv *il) D_EEPROM("Parsing data for %d channels.\n", il->channel_count); il->channel_info = - kzalloc(sizeof(struct il_channel_info) * il->channel_count, + kcalloc(il->channel_count, sizeof(struct il_channel_info), GFP_KERNEL); if (!il->channel_info) { IL_ERR("Could not allocate channel_info\n"); @@ -3041,9 +3041,9 @@ il_tx_queue_init(struct il_priv *il, u32 txq_id) } txq->meta = - kzalloc(sizeof(struct il_cmd_meta) * actual_slots, GFP_KERNEL); + kcalloc(actual_slots, sizeof(struct il_cmd_meta), GFP_KERNEL); txq->cmd = - kzalloc(sizeof(struct il_device_cmd *) * actual_slots, GFP_KERNEL); + kcalloc(actual_slots, sizeof(struct il_device_cmd *), GFP_KERNEL); if (!txq->meta || !txq->cmd) goto out_free_arrays; @@ -3455,7 +3455,7 @@ il_init_geos(struct il_priv *il) } channels = - kzalloc(sizeof(struct ieee80211_channel) * il->channel_count, + kcalloc(il->channel_count, sizeof(struct ieee80211_channel), GFP_KERNEL); if (!channels) return -ENOMEM; @@ -4654,8 +4654,9 @@ il_alloc_txq_mem(struct il_priv *il) { if (!il->txq) il->txq = - kzalloc(sizeof(struct il_tx_queue) * - il->cfg->num_of_queues, GFP_KERNEL); + kcalloc(il->cfg->num_of_queues, + sizeof(struct il_tx_queue), + GFP_KERNEL); if (!il->txq) { IL_ERR("Not enough memory for txq\n"); return -ENOMEM; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 4b3753d78d03..11ecdf63b732 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -564,7 +564,7 @@ iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm, else blacklist_len = IWL_SCAN_MAX_BLACKLIST_LEN; - blacklist = kzalloc(sizeof(*blacklist) * blacklist_len, GFP_KERNEL); + blacklist = kcalloc(blacklist_len, sizeof(*blacklist), GFP_KERNEL); if (!blacklist) return -ENOMEM; diff --git a/drivers/net/wireless/intersil/hostap/hostap_info.c b/drivers/net/wireless/intersil/hostap/hostap_info.c index de8a099a9386..da8c30f10d92 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_info.c +++ b/drivers/net/wireless/intersil/hostap/hostap_info.c @@ -271,8 +271,9 @@ static void prism2_info_scanresults(local_info_t *local, unsigned char *buf, left -= 4; new_count = left / sizeof(struct hfa384x_scan_result); - results = kmalloc(new_count * sizeof(struct hfa384x_hostscan_result), - GFP_ATOMIC); + results = kmalloc_array(new_count, + sizeof(struct hfa384x_hostscan_result), + GFP_ATOMIC); if (results == NULL) return; diff --git a/drivers/net/wireless/intersil/hostap/hostap_ioctl.c b/drivers/net/wireless/intersil/hostap/hostap_ioctl.c index c1bc0a6ef300..1ca9731d9b14 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_ioctl.c +++ b/drivers/net/wireless/intersil/hostap/hostap_ioctl.c @@ -513,8 +513,8 @@ static int prism2_ioctl_giwaplist(struct net_device *dev, return -EOPNOTSUPP; } - addr = kmalloc(sizeof(struct sockaddr) * IW_MAX_AP, GFP_KERNEL); - qual = kmalloc(sizeof(struct iw_quality) * IW_MAX_AP, GFP_KERNEL); + addr = kmalloc_array(IW_MAX_AP, sizeof(struct sockaddr), GFP_KERNEL); + qual = kmalloc_array(IW_MAX_AP, sizeof(struct iw_quality), GFP_KERNEL); if (addr == NULL || qual == NULL) { kfree(addr); kfree(qual); diff --git a/drivers/net/wireless/intersil/p54/eeprom.c b/drivers/net/wireless/intersil/p54/eeprom.c index d4c73d39336f..de2ef95c386c 100644 --- a/drivers/net/wireless/intersil/p54/eeprom.c +++ b/drivers/net/wireless/intersil/p54/eeprom.c @@ -161,8 +161,9 @@ static int p54_generate_band(struct ieee80211_hw *dev, if (!tmp) goto err_out; - tmp->channels = kzalloc(sizeof(struct ieee80211_channel) * - list->band_channel_num[band], GFP_KERNEL); + tmp->channels = kcalloc(list->band_channel_num[band], + sizeof(struct ieee80211_channel), + GFP_KERNEL); if (!tmp->channels) goto err_out; @@ -344,7 +345,7 @@ static int p54_generate_channel_lists(struct ieee80211_hw *dev) goto free; } priv->chan_num = max_channel_num; - priv->survey = kzalloc(sizeof(struct survey_info) * max_channel_num, + priv->survey = kcalloc(max_channel_num, sizeof(struct survey_info), GFP_KERNEL); if (!priv->survey) { ret = -ENOMEM; @@ -352,8 +353,9 @@ static int p54_generate_channel_lists(struct ieee80211_hw *dev) } list->max_entries = max_channel_num; - list->channels = kzalloc(sizeof(struct p54_channel_entry) * - max_channel_num, GFP_KERNEL); + list->channels = kcalloc(max_channel_num, + sizeof(struct p54_channel_entry), + GFP_KERNEL); if (!list->channels) { ret = -ENOMEM; goto free; diff --git a/drivers/net/wireless/intersil/prism54/oid_mgt.c b/drivers/net/wireless/intersil/prism54/oid_mgt.c index 6528ed5b9b1d..6d57e1cbcc07 100644 --- a/drivers/net/wireless/intersil/prism54/oid_mgt.c +++ b/drivers/net/wireless/intersil/prism54/oid_mgt.c @@ -244,7 +244,7 @@ mgt_init(islpci_private *priv) /* Alloc the cache */ for (i = 0; i < OID_NUM_LAST; i++) { if (isl_oid[i].flags & OID_FLAG_CACHED) { - priv->mib[i] = kzalloc(isl_oid[i].size * + priv->mib[i] = kcalloc(isl_oid[i].size, (isl_oid[i].range + 1), GFP_KERNEL); if (!priv->mib[i]) diff --git a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c index 1edcddaf7b4b..7ab44cd32a9d 100644 --- a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c @@ -399,8 +399,8 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta, new_node->win_size = win_size; - new_node->rx_reorder_ptr = kzalloc(sizeof(void *) * win_size, - GFP_KERNEL); + new_node->rx_reorder_ptr = kcalloc(win_size, sizeof(void *), + GFP_KERNEL); if (!new_node->rx_reorder_ptr) { kfree((u8 *) new_node); mwifiex_dbg(priv->adapter, ERROR, diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index a67e2d66ac9d..4b5ae9098504 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -4242,8 +4242,8 @@ int mwifiex_init_channel_scan_gap(struct mwifiex_adapter *adapter) * additional active scan request for hidden SSIDs on passive channels. */ adapter->num_in_chan_stats = 2 * (n_channels_bg + n_channels_a); - adapter->chan_stats = vmalloc(sizeof(*adapter->chan_stats) * - adapter->num_in_chan_stats); + adapter->chan_stats = vmalloc(array_size(sizeof(*adapter->chan_stats), + adapter->num_in_chan_stats)); if (!adapter->chan_stats) return -ENOMEM; diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c index 47d2dcc3f28f..dfdcbc4f141a 100644 --- a/drivers/net/wireless/marvell/mwifiex/sdio.c +++ b/drivers/net/wireless/marvell/mwifiex/sdio.c @@ -2106,15 +2106,16 @@ static int mwifiex_init_sdio(struct mwifiex_adapter *adapter) return -ENOMEM; /* Allocate skb pointer buffers */ - card->mpa_rx.skb_arr = kzalloc((sizeof(void *)) * - card->mp_agg_pkt_limit, GFP_KERNEL); + card->mpa_rx.skb_arr = kcalloc(card->mp_agg_pkt_limit, sizeof(void *), + GFP_KERNEL); if (!card->mpa_rx.skb_arr) { kfree(card->mp_regs); return -ENOMEM; } - card->mpa_rx.len_arr = kzalloc(sizeof(*card->mpa_rx.len_arr) * - card->mp_agg_pkt_limit, GFP_KERNEL); + card->mpa_rx.len_arr = kcalloc(card->mp_agg_pkt_limit, + sizeof(*card->mpa_rx.len_arr), + GFP_KERNEL); if (!card->mpa_rx.len_arr) { kfree(card->mp_regs); kfree(card->mpa_rx.skb_arr); diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index fcd079a96782..d62e34e7eadf 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -181,7 +181,7 @@ mt76_init_sband(struct mt76_dev *dev, struct mt76_sband *msband, if (!chanlist) return -ENOMEM; - msband->chan = devm_kzalloc(dev->dev, n_chan * sizeof(*msband->chan), + msband->chan = devm_kcalloc(dev->dev, n_chan, sizeof(*msband->chan), GFP_KERNEL); if (!msband->chan) return -ENOMEM; diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c b/drivers/net/wireless/quantenna/qtnfmac/commands.c index 5eb143667539..c5d94a95e21a 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/commands.c +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c @@ -1216,7 +1216,7 @@ static int qtnf_parse_variable_mac_info(struct qtnf_wmac *mac, return -EINVAL; } - limits = kzalloc(sizeof(*limits) * rec->n_limits, + limits = kcalloc(rec->n_limits, sizeof(*limits), GFP_KERNEL); if (!limits) return -ENOMEM; diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c b/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c index 0eee479583b8..acc399b5574e 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c @@ -397,7 +397,7 @@ static ssize_t rt2x00debug_read_crypto_stats(struct file *file, if (*offset) return 0; - data = kzalloc((1 + CIPHER_MAX) * MAX_LINE_LENGTH, GFP_KERNEL); + data = kcalloc(1 + CIPHER_MAX, MAX_LINE_LENGTH, GFP_KERNEL); if (!data) return -ENOMEM; diff --git a/drivers/net/wireless/realtek/rtlwifi/efuse.c b/drivers/net/wireless/realtek/rtlwifi/efuse.c index fd13d4ef53b8..9729e51fce38 100644 --- a/drivers/net/wireless/realtek/rtlwifi/efuse.c +++ b/drivers/net/wireless/realtek/rtlwifi/efuse.c @@ -258,8 +258,8 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf) } /* allocate memory for efuse_tbl and efuse_word */ - efuse_tbl = kzalloc(rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE] * - sizeof(u8), GFP_ATOMIC); + efuse_tbl = kzalloc(rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE], + GFP_ATOMIC); if (!efuse_tbl) return; efuse_word = kcalloc(EFUSE_MAX_WORD_UNIT, sizeof(u16 *), GFP_ATOMIC); diff --git a/drivers/net/wireless/realtek/rtlwifi/usb.c b/drivers/net/wireless/realtek/rtlwifi/usb.c index ce3103bb8ebb..f9faffc498bc 100644 --- a/drivers/net/wireless/realtek/rtlwifi/usb.c +++ b/drivers/net/wireless/realtek/rtlwifi/usb.c @@ -1048,7 +1048,7 @@ int rtl_usb_probe(struct usb_interface *intf, } rtlpriv = hw->priv; rtlpriv->hw = hw; - rtlpriv->usb_data = kzalloc(RTL_USB_MAX_RX_COUNT * sizeof(u32), + rtlpriv->usb_data = kcalloc(RTL_USB_MAX_RX_COUNT, sizeof(u32), GFP_KERNEL); if (!rtlpriv->usb_data) return -ENOMEM; diff --git a/drivers/net/wireless/st/cw1200/queue.c b/drivers/net/wireless/st/cw1200/queue.c index 5153d2cfd991..7c31b63b8258 100644 --- a/drivers/net/wireless/st/cw1200/queue.c +++ b/drivers/net/wireless/st/cw1200/queue.c @@ -154,7 +154,7 @@ int cw1200_queue_stats_init(struct cw1200_queue_stats *stats, spin_lock_init(&stats->lock); init_waitqueue_head(&stats->wait_link_id_empty); - stats->link_map_cache = kzalloc(sizeof(int) * map_capacity, + stats->link_map_cache = kcalloc(map_capacity, sizeof(int), GFP_KERNEL); if (!stats->link_map_cache) return -ENOMEM; @@ -181,13 +181,13 @@ int cw1200_queue_init(struct cw1200_queue *queue, spin_lock_init(&queue->lock); timer_setup(&queue->gc, cw1200_queue_gc, 0); - queue->pool = kzalloc(sizeof(struct cw1200_queue_item) * capacity, - GFP_KERNEL); + queue->pool = kcalloc(capacity, sizeof(struct cw1200_queue_item), + GFP_KERNEL); if (!queue->pool) return -ENOMEM; - queue->link_map_cache = kzalloc(sizeof(int) * stats->map_capacity, - GFP_KERNEL); + queue->link_map_cache = kcalloc(stats->map_capacity, sizeof(int), + GFP_KERNEL); if (!queue->link_map_cache) { kfree(queue->pool); queue->pool = NULL; diff --git a/drivers/net/wireless/st/cw1200/scan.c b/drivers/net/wireless/st/cw1200/scan.c index cc2ce60f4f09..67213f11acbd 100644 --- a/drivers/net/wireless/st/cw1200/scan.c +++ b/drivers/net/wireless/st/cw1200/scan.c @@ -230,9 +230,9 @@ void cw1200_scan_work(struct work_struct *work) scan.type = WSM_SCAN_TYPE_BACKGROUND; scan.flags = WSM_SCAN_FLAG_FORCE_BACKGROUND; } - scan.ch = kzalloc( - sizeof(struct wsm_scan_ch) * (it - priv->scan.curr), - GFP_KERNEL); + scan.ch = kcalloc(it - priv->scan.curr, + sizeof(struct wsm_scan_ch), + GFP_KERNEL); if (!scan.ch) { priv->scan.status = -ENOMEM; goto fail; diff --git a/drivers/net/wireless/zydas/zd1211rw/zd_mac.c b/drivers/net/wireless/zydas/zd1211rw/zd_mac.c index b01b44a5d16e..1f6d9f357e57 100644 --- a/drivers/net/wireless/zydas/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zydas/zd1211rw/zd_mac.c @@ -732,7 +732,8 @@ static int zd_mac_config_beacon(struct ieee80211_hw *hw, struct sk_buff *beacon, /* Alloc memory for full beacon write at once. */ num_cmds = 1 + zd_chip_is_zd1211b(&mac->chip) + full_len; - ioreqs = kmalloc(num_cmds * sizeof(struct zd_ioreq32), GFP_KERNEL); + ioreqs = kmalloc_array(num_cmds, sizeof(struct zd_ioreq32), + GFP_KERNEL); if (!ioreqs) { r = -ENOMEM; goto out_nofree; diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c index e1aef253601e..cd51492ae6c2 100644 --- a/drivers/net/xen-netback/xenbus.c +++ b/drivers/net/xen-netback/xenbus.c @@ -977,8 +977,8 @@ static void connect(struct backend_info *be) } /* Use the number of queues requested by the frontend */ - be->vif->queues = vzalloc(requested_num_queues * - sizeof(struct xenvif_queue)); + be->vif->queues = vzalloc(array_size(requested_num_queues, + sizeof(struct xenvif_queue))); if (!be->vif->queues) { xenbus_dev_fatal(dev, -ENOMEM, "allocating queues"); diff --git a/drivers/nfc/fdp/i2c.c b/drivers/nfc/fdp/i2c.c index c4da50e07bbc..d8d70dd830b0 100644 --- a/drivers/nfc/fdp/i2c.c +++ b/drivers/nfc/fdp/i2c.c @@ -259,8 +259,8 @@ static void fdp_nci_i2c_read_device_properties(struct device *dev, /* Add 1 to the length to inclue the length byte itself */ len++; - *fw_vsc_cfg = devm_kmalloc(dev, - len * sizeof(**fw_vsc_cfg), + *fw_vsc_cfg = devm_kmalloc_array(dev, + len, sizeof(**fw_vsc_cfg), GFP_KERNEL); r = device_property_read_u8_array(dev, FDP_DP_FW_VSC_CFG_NAME, diff --git a/drivers/ntb/hw/amd/ntb_hw_amd.c b/drivers/ntb/hw/amd/ntb_hw_amd.c index 3cfa46876239..efb214fc545a 100644 --- a/drivers/ntb/hw/amd/ntb_hw_amd.c +++ b/drivers/ntb/hw/amd/ntb_hw_amd.c @@ -592,12 +592,12 @@ static int ndev_init_isr(struct amd_ntb_dev *ndev, ndev->db_mask = ndev->db_valid_mask; /* Try to set up msix irq */ - ndev->vec = kzalloc_node(msix_max * sizeof(*ndev->vec), + ndev->vec = kcalloc_node(msix_max, sizeof(*ndev->vec), GFP_KERNEL, node); if (!ndev->vec) goto err_msix_vec_alloc; - ndev->msix = kzalloc_node(msix_max * sizeof(*ndev->msix), + ndev->msix = kcalloc_node(msix_max, sizeof(*ndev->msix), GFP_KERNEL, node); if (!ndev->msix) goto err_msix_alloc; diff --git a/drivers/ntb/hw/idt/ntb_hw_idt.c b/drivers/ntb/hw/idt/ntb_hw_idt.c index 8d98872d0983..dbe72f116017 100644 --- a/drivers/ntb/hw/idt/ntb_hw_idt.c +++ b/drivers/ntb/hw/idt/ntb_hw_idt.c @@ -1401,7 +1401,7 @@ static int idt_ntb_peer_mw_clear_trans(struct ntb_dev *ntb, int pidx, * 5. Doorbell operations * * Doorbell functionality of IDT PCIe-switches is pretty unusual. First of - * all there is global doorbell register which state can by changed by any + * all there is global doorbell register which state can be changed by any * NT-function of the IDT device in accordance with global permissions. These * permissions configs are not supported by NTB API, so it must be done by * either BIOS or EEPROM settings. In the same way the state of the global diff --git a/drivers/ntb/hw/intel/Makefile b/drivers/ntb/hw/intel/Makefile index 1b434568d2ad..4ff22af967c6 100644 --- a/drivers/ntb/hw/intel/Makefile +++ b/drivers/ntb/hw/intel/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_NTB_INTEL) += ntb_hw_intel.o +ntb_hw_intel-y := ntb_hw_gen1.o ntb_hw_gen3.o diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_gen1.c index 156b45cd4a19..6aa573227279 100644 --- a/drivers/ntb/hw/intel/ntb_hw_intel.c +++ b/drivers/ntb/hw/intel/ntb_hw_gen1.c @@ -45,9 +45,6 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Intel PCIe NTB Linux driver - * - * Contact Information: - * Jon Mason <jon.mason@intel.com> */ #include <linux/debugfs.h> @@ -61,6 +58,8 @@ #include <linux/ntb.h> #include "ntb_hw_intel.h" +#include "ntb_hw_gen1.h" +#include "ntb_hw_gen3.h" #define NTB_NAME "ntb_hw_intel" #define NTB_DESC "Intel(R) PCI-E Non-Transparent Bridge Driver" @@ -80,14 +79,7 @@ static const struct intel_ntb_alt_reg xeon_sec_reg; static const struct intel_ntb_alt_reg xeon_b2b_reg; static const struct intel_ntb_xlat_reg xeon_pri_xlat; static const struct intel_ntb_xlat_reg xeon_sec_xlat; -static struct intel_b2b_addr xeon_b2b_usd_addr; -static struct intel_b2b_addr xeon_b2b_dsd_addr; -static const struct intel_ntb_reg skx_reg; -static const struct intel_ntb_alt_reg skx_pri_reg; -static const struct intel_ntb_alt_reg skx_b2b_reg; -static const struct intel_ntb_xlat_reg skx_sec_xlat; static const struct ntb_dev_ops intel_ntb_ops; -static const struct ntb_dev_ops intel_ntb3_ops; static const struct file_operations intel_ntb_debugfs_info; static struct dentry *debugfs_dir; @@ -146,68 +138,8 @@ module_param_named(xeon_b2b_dsd_bar5_addr32, MODULE_PARM_DESC(xeon_b2b_dsd_bar5_addr32, "XEON B2B DSD split-BAR 5 32-bit address"); -static inline enum ntb_topo xeon_ppd_topo(struct intel_ntb_dev *ndev, u8 ppd); -static int xeon_init_isr(struct intel_ntb_dev *ndev); - -#ifndef ioread64 -#ifdef readq -#define ioread64 readq -#else -#define ioread64 _ioread64 -static inline u64 _ioread64(void __iomem *mmio) -{ - u64 low, high; - - low = ioread32(mmio); - high = ioread32(mmio + sizeof(u32)); - return low | (high << 32); -} -#endif -#endif - -#ifndef iowrite64 -#ifdef writeq -#define iowrite64 writeq -#else -#define iowrite64 _iowrite64 -static inline void _iowrite64(u64 val, void __iomem *mmio) -{ - iowrite32(val, mmio); - iowrite32(val >> 32, mmio + sizeof(u32)); -} -#endif -#endif - -static inline int pdev_is_xeon(struct pci_dev *pdev) -{ - switch (pdev->device) { - case PCI_DEVICE_ID_INTEL_NTB_SS_JSF: - case PCI_DEVICE_ID_INTEL_NTB_SS_SNB: - case PCI_DEVICE_ID_INTEL_NTB_SS_IVT: - case PCI_DEVICE_ID_INTEL_NTB_SS_HSX: - case PCI_DEVICE_ID_INTEL_NTB_SS_BDX: - case PCI_DEVICE_ID_INTEL_NTB_PS_JSF: - case PCI_DEVICE_ID_INTEL_NTB_PS_SNB: - case PCI_DEVICE_ID_INTEL_NTB_PS_IVT: - case PCI_DEVICE_ID_INTEL_NTB_PS_HSX: - case PCI_DEVICE_ID_INTEL_NTB_PS_BDX: - case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF: - case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB: - case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT: - case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX: - case PCI_DEVICE_ID_INTEL_NTB_B2B_BDX: - return 1; - } - return 0; -} - -static inline int pdev_is_skx_xeon(struct pci_dev *pdev) -{ - if (pdev->device == PCI_DEVICE_ID_INTEL_NTB_B2B_SKX) - return 1; - return 0; -} +static int xeon_init_isr(struct intel_ntb_dev *ndev); static inline void ndev_reset_unsafe_flags(struct intel_ntb_dev *ndev) { @@ -241,7 +173,7 @@ static inline int ndev_ignore_unsafe(struct intel_ntb_dev *ndev, return !!flag; } -static int ndev_mw_to_bar(struct intel_ntb_dev *ndev, int idx) +int ndev_mw_to_bar(struct intel_ntb_dev *ndev, int idx) { if (idx < 0 || idx >= ndev->mw_count) return -EINVAL; @@ -268,7 +200,7 @@ static inline int ndev_db_addr(struct intel_ntb_dev *ndev, return 0; } -static inline u64 ndev_db_read(struct intel_ntb_dev *ndev, +u64 ndev_db_read(struct intel_ntb_dev *ndev, void __iomem *mmio) { if (ndev_is_unsafe(ndev, NTB_UNSAFE_DB)) @@ -277,7 +209,7 @@ static inline u64 ndev_db_read(struct intel_ntb_dev *ndev, return ndev->reg->db_ioread(mmio); } -static inline int ndev_db_write(struct intel_ntb_dev *ndev, u64 db_bits, +int ndev_db_write(struct intel_ntb_dev *ndev, u64 db_bits, void __iomem *mmio) { if (ndev_is_unsafe(ndev, NTB_UNSAFE_DB)) @@ -429,7 +361,7 @@ static irqreturn_t ndev_irq_isr(int irq, void *dev) return ndev_interrupt(ndev, irq - ndev->ntb.pdev->irq); } -static int ndev_init_isr(struct intel_ntb_dev *ndev, +int ndev_init_isr(struct intel_ntb_dev *ndev, int msix_min, int msix_max, int msix_shift, int total_shift) { @@ -448,12 +380,12 @@ static int ndev_init_isr(struct intel_ntb_dev *ndev, /* Try to set up msix irq */ - ndev->vec = kzalloc_node(msix_max * sizeof(*ndev->vec), + ndev->vec = kcalloc_node(msix_max, sizeof(*ndev->vec), GFP_KERNEL, node); if (!ndev->vec) goto err_msix_vec_alloc; - ndev->msix = kzalloc_node(msix_max * sizeof(*ndev->msix), + ndev->msix = kcalloc_node(msix_max, sizeof(*ndev->msix), GFP_KERNEL, node); if (!ndev->msix) goto err_msix_alloc; @@ -557,169 +489,6 @@ static void ndev_deinit_isr(struct intel_ntb_dev *ndev) } } -static ssize_t ndev_ntb3_debugfs_read(struct file *filp, char __user *ubuf, - size_t count, loff_t *offp) -{ - struct intel_ntb_dev *ndev; - void __iomem *mmio; - char *buf; - size_t buf_size; - ssize_t ret, off; - union { u64 v64; u32 v32; u16 v16; } u; - - ndev = filp->private_data; - mmio = ndev->self_mmio; - - buf_size = min(count, 0x800ul); - - buf = kmalloc(buf_size, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - off = 0; - - off += scnprintf(buf + off, buf_size - off, - "NTB Device Information:\n"); - - off += scnprintf(buf + off, buf_size - off, - "Connection Topology -\t%s\n", - ntb_topo_string(ndev->ntb.topo)); - - off += scnprintf(buf + off, buf_size - off, - "NTB CTL -\t\t%#06x\n", ndev->ntb_ctl); - off += scnprintf(buf + off, buf_size - off, - "LNK STA -\t\t%#06x\n", ndev->lnk_sta); - - if (!ndev->reg->link_is_up(ndev)) - off += scnprintf(buf + off, buf_size - off, - "Link Status -\t\tDown\n"); - else { - off += scnprintf(buf + off, buf_size - off, - "Link Status -\t\tUp\n"); - off += scnprintf(buf + off, buf_size - off, - "Link Speed -\t\tPCI-E Gen %u\n", - NTB_LNK_STA_SPEED(ndev->lnk_sta)); - off += scnprintf(buf + off, buf_size - off, - "Link Width -\t\tx%u\n", - NTB_LNK_STA_WIDTH(ndev->lnk_sta)); - } - - off += scnprintf(buf + off, buf_size - off, - "Memory Window Count -\t%u\n", ndev->mw_count); - off += scnprintf(buf + off, buf_size - off, - "Scratchpad Count -\t%u\n", ndev->spad_count); - off += scnprintf(buf + off, buf_size - off, - "Doorbell Count -\t%u\n", ndev->db_count); - off += scnprintf(buf + off, buf_size - off, - "Doorbell Vector Count -\t%u\n", ndev->db_vec_count); - off += scnprintf(buf + off, buf_size - off, - "Doorbell Vector Shift -\t%u\n", ndev->db_vec_shift); - - off += scnprintf(buf + off, buf_size - off, - "Doorbell Valid Mask -\t%#llx\n", ndev->db_valid_mask); - off += scnprintf(buf + off, buf_size - off, - "Doorbell Link Mask -\t%#llx\n", ndev->db_link_mask); - off += scnprintf(buf + off, buf_size - off, - "Doorbell Mask Cached -\t%#llx\n", ndev->db_mask); - - u.v64 = ndev_db_read(ndev, mmio + ndev->self_reg->db_mask); - off += scnprintf(buf + off, buf_size - off, - "Doorbell Mask -\t\t%#llx\n", u.v64); - - u.v64 = ndev_db_read(ndev, mmio + ndev->self_reg->db_bell); - off += scnprintf(buf + off, buf_size - off, - "Doorbell Bell -\t\t%#llx\n", u.v64); - - off += scnprintf(buf + off, buf_size - off, - "\nNTB Incoming XLAT:\n"); - - u.v64 = ioread64(mmio + SKX_IMBAR1XBASE_OFFSET); - off += scnprintf(buf + off, buf_size - off, - "IMBAR1XBASE -\t\t%#018llx\n", u.v64); - - u.v64 = ioread64(mmio + SKX_IMBAR2XBASE_OFFSET); - off += scnprintf(buf + off, buf_size - off, - "IMBAR2XBASE -\t\t%#018llx\n", u.v64); - - u.v64 = ioread64(mmio + SKX_IMBAR1XLMT_OFFSET); - off += scnprintf(buf + off, buf_size - off, - "IMBAR1XLMT -\t\t\t%#018llx\n", u.v64); - - u.v64 = ioread64(mmio + SKX_IMBAR2XLMT_OFFSET); - off += scnprintf(buf + off, buf_size - off, - "IMBAR2XLMT -\t\t\t%#018llx\n", u.v64); - - if (ntb_topo_is_b2b(ndev->ntb.topo)) { - off += scnprintf(buf + off, buf_size - off, - "\nNTB Outgoing B2B XLAT:\n"); - - u.v64 = ioread64(mmio + SKX_EMBAR1XBASE_OFFSET); - off += scnprintf(buf + off, buf_size - off, - "EMBAR1XBASE -\t\t%#018llx\n", u.v64); - - u.v64 = ioread64(mmio + SKX_EMBAR2XBASE_OFFSET); - off += scnprintf(buf + off, buf_size - off, - "EMBAR2XBASE -\t\t%#018llx\n", u.v64); - - u.v64 = ioread64(mmio + SKX_EMBAR1XLMT_OFFSET); - off += scnprintf(buf + off, buf_size - off, - "EMBAR1XLMT -\t\t%#018llx\n", u.v64); - - u.v64 = ioread64(mmio + SKX_EMBAR2XLMT_OFFSET); - off += scnprintf(buf + off, buf_size - off, - "EMBAR2XLMT -\t\t%#018llx\n", u.v64); - - off += scnprintf(buf + off, buf_size - off, - "\nNTB Secondary BAR:\n"); - - u.v64 = ioread64(mmio + SKX_EMBAR0_OFFSET); - off += scnprintf(buf + off, buf_size - off, - "EMBAR0 -\t\t%#018llx\n", u.v64); - - u.v64 = ioread64(mmio + SKX_EMBAR1_OFFSET); - off += scnprintf(buf + off, buf_size - off, - "EMBAR1 -\t\t%#018llx\n", u.v64); - - u.v64 = ioread64(mmio + SKX_EMBAR2_OFFSET); - off += scnprintf(buf + off, buf_size - off, - "EMBAR2 -\t\t%#018llx\n", u.v64); - } - - off += scnprintf(buf + off, buf_size - off, - "\nNTB Statistics:\n"); - - u.v16 = ioread16(mmio + SKX_USMEMMISS_OFFSET); - off += scnprintf(buf + off, buf_size - off, - "Upstream Memory Miss -\t%u\n", u.v16); - - off += scnprintf(buf + off, buf_size - off, - "\nNTB Hardware Errors:\n"); - - if (!pci_read_config_word(ndev->ntb.pdev, - SKX_DEVSTS_OFFSET, &u.v16)) - off += scnprintf(buf + off, buf_size - off, - "DEVSTS -\t\t%#06x\n", u.v16); - - if (!pci_read_config_word(ndev->ntb.pdev, - SKX_LINK_STATUS_OFFSET, &u.v16)) - off += scnprintf(buf + off, buf_size - off, - "LNKSTS -\t\t%#06x\n", u.v16); - - if (!pci_read_config_dword(ndev->ntb.pdev, - SKX_UNCERRSTS_OFFSET, &u.v32)) - off += scnprintf(buf + off, buf_size - off, - "UNCERRSTS -\t\t%#06x\n", u.v32); - - if (!pci_read_config_dword(ndev->ntb.pdev, - SKX_CORERRSTS_OFFSET, &u.v32)) - off += scnprintf(buf + off, buf_size - off, - "CORERRSTS -\t\t%#06x\n", u.v32); - - ret = simple_read_from_buffer(ubuf, count, offp, buf, off); - kfree(buf); - return ret; -} - static ssize_t ndev_ntb_debugfs_read(struct file *filp, char __user *ubuf, size_t count, loff_t *offp) { @@ -879,7 +648,7 @@ static ssize_t ndev_ntb_debugfs_read(struct file *filp, char __user *ubuf, "LMT45 -\t\t\t%#018llx\n", u.v64); } - if (pdev_is_xeon(pdev)) { + if (pdev_is_gen1(pdev)) { if (ntb_topo_is_b2b(ndev->ntb.topo)) { off += scnprintf(buf + off, buf_size - off, "\nNTB Outgoing B2B XLAT:\n"); @@ -991,9 +760,9 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf, { struct intel_ntb_dev *ndev = filp->private_data; - if (pdev_is_xeon(ndev->ntb.pdev)) + if (pdev_is_gen1(ndev->ntb.pdev)) return ndev_ntb_debugfs_read(filp, ubuf, count, offp); - else if (pdev_is_skx_xeon(ndev->ntb.pdev)) + else if (pdev_is_gen3(ndev->ntb.pdev)) return ndev_ntb3_debugfs_read(filp, ubuf, count, offp); return -ENXIO; @@ -1023,7 +792,7 @@ static void ndev_deinit_debugfs(struct intel_ntb_dev *ndev) debugfs_remove_recursive(ndev->debugfs_dir); } -static int intel_ntb_mw_count(struct ntb_dev *ntb, int pidx) +int intel_ntb_mw_count(struct ntb_dev *ntb, int pidx) { if (pidx != NTB_DEF_PEER_IDX) return -EINVAL; @@ -1031,10 +800,10 @@ static int intel_ntb_mw_count(struct ntb_dev *ntb, int pidx) return ntb_ndev(ntb)->mw_count; } -static int intel_ntb_mw_get_align(struct ntb_dev *ntb, int pidx, int idx, - resource_size_t *addr_align, - resource_size_t *size_align, - resource_size_t *size_max) +int intel_ntb_mw_get_align(struct ntb_dev *ntb, int pidx, int idx, + resource_size_t *addr_align, + resource_size_t *size_align, + resource_size_t *size_max) { struct intel_ntb_dev *ndev = ntb_ndev(ntb); resource_size_t bar_size, mw_size; @@ -1170,9 +939,8 @@ static int intel_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx, return 0; } -static u64 intel_ntb_link_is_up(struct ntb_dev *ntb, - enum ntb_speed *speed, - enum ntb_width *width) +u64 intel_ntb_link_is_up(struct ntb_dev *ntb, enum ntb_speed *speed, + enum ntb_width *width) { struct intel_ntb_dev *ndev = ntb_ndev(ntb); @@ -1224,7 +992,7 @@ static int intel_ntb_link_enable(struct ntb_dev *ntb, return 0; } -static int intel_ntb_link_disable(struct ntb_dev *ntb) +int intel_ntb_link_disable(struct ntb_dev *ntb) { struct intel_ntb_dev *ndev; u32 ntb_cntl; @@ -1248,14 +1016,14 @@ static int intel_ntb_link_disable(struct ntb_dev *ntb) return 0; } -static int intel_ntb_peer_mw_count(struct ntb_dev *ntb) +int intel_ntb_peer_mw_count(struct ntb_dev *ntb) { /* Numbers of inbound and outbound memory windows match */ return ntb_ndev(ntb)->mw_count; } -static int intel_ntb_peer_mw_get_addr(struct ntb_dev *ntb, int idx, - phys_addr_t *base, resource_size_t *size) +int intel_ntb_peer_mw_get_addr(struct ntb_dev *ntb, int idx, + phys_addr_t *base, resource_size_t *size) { struct intel_ntb_dev *ndev = ntb_ndev(ntb); int bar; @@ -1283,12 +1051,12 @@ static int intel_ntb_db_is_unsafe(struct ntb_dev *ntb) return ndev_ignore_unsafe(ntb_ndev(ntb), NTB_UNSAFE_DB); } -static u64 intel_ntb_db_valid_mask(struct ntb_dev *ntb) +u64 intel_ntb_db_valid_mask(struct ntb_dev *ntb) { return ntb_ndev(ntb)->db_valid_mask; } -static int intel_ntb_db_vector_count(struct ntb_dev *ntb) +int intel_ntb_db_vector_count(struct ntb_dev *ntb) { struct intel_ntb_dev *ndev; @@ -1297,7 +1065,7 @@ static int intel_ntb_db_vector_count(struct ntb_dev *ntb) return ndev->db_vec_count; } -static u64 intel_ntb_db_vector_mask(struct ntb_dev *ntb, int db_vector) +u64 intel_ntb_db_vector_mask(struct ntb_dev *ntb, int db_vector) { struct intel_ntb_dev *ndev = ntb_ndev(ntb); @@ -1325,7 +1093,7 @@ static int intel_ntb_db_clear(struct ntb_dev *ntb, u64 db_bits) ndev->self_reg->db_bell); } -static int intel_ntb_db_set_mask(struct ntb_dev *ntb, u64 db_bits) +int intel_ntb_db_set_mask(struct ntb_dev *ntb, u64 db_bits) { struct intel_ntb_dev *ndev = ntb_ndev(ntb); @@ -1334,7 +1102,7 @@ static int intel_ntb_db_set_mask(struct ntb_dev *ntb, u64 db_bits) ndev->self_reg->db_mask); } -static int intel_ntb_db_clear_mask(struct ntb_dev *ntb, u64 db_bits) +int intel_ntb_db_clear_mask(struct ntb_dev *ntb, u64 db_bits) { struct intel_ntb_dev *ndev = ntb_ndev(ntb); @@ -1343,9 +1111,8 @@ static int intel_ntb_db_clear_mask(struct ntb_dev *ntb, u64 db_bits) ndev->self_reg->db_mask); } -static int intel_ntb_peer_db_addr(struct ntb_dev *ntb, - phys_addr_t *db_addr, - resource_size_t *db_size) +int intel_ntb_peer_db_addr(struct ntb_dev *ntb, phys_addr_t *db_addr, + resource_size_t *db_size) { struct intel_ntb_dev *ndev = ntb_ndev(ntb); @@ -1362,12 +1129,12 @@ static int intel_ntb_peer_db_set(struct ntb_dev *ntb, u64 db_bits) ndev->peer_reg->db_bell); } -static int intel_ntb_spad_is_unsafe(struct ntb_dev *ntb) +int intel_ntb_spad_is_unsafe(struct ntb_dev *ntb) { return ndev_ignore_unsafe(ntb_ndev(ntb), NTB_UNSAFE_SPAD); } -static int intel_ntb_spad_count(struct ntb_dev *ntb) +int intel_ntb_spad_count(struct ntb_dev *ntb) { struct intel_ntb_dev *ndev; @@ -1376,7 +1143,7 @@ static int intel_ntb_spad_count(struct ntb_dev *ntb) return ndev->spad_count; } -static u32 intel_ntb_spad_read(struct ntb_dev *ntb, int idx) +u32 intel_ntb_spad_read(struct ntb_dev *ntb, int idx) { struct intel_ntb_dev *ndev = ntb_ndev(ntb); @@ -1385,8 +1152,7 @@ static u32 intel_ntb_spad_read(struct ntb_dev *ntb, int idx) ndev->self_reg->spad); } -static int intel_ntb_spad_write(struct ntb_dev *ntb, - int idx, u32 val) +int intel_ntb_spad_write(struct ntb_dev *ntb, int idx, u32 val) { struct intel_ntb_dev *ndev = ntb_ndev(ntb); @@ -1395,8 +1161,8 @@ static int intel_ntb_spad_write(struct ntb_dev *ntb, ndev->self_reg->spad); } -static int intel_ntb_peer_spad_addr(struct ntb_dev *ntb, int pidx, int sidx, - phys_addr_t *spad_addr) +int intel_ntb_peer_spad_addr(struct ntb_dev *ntb, int pidx, int sidx, + phys_addr_t *spad_addr) { struct intel_ntb_dev *ndev = ntb_ndev(ntb); @@ -1404,7 +1170,7 @@ static int intel_ntb_peer_spad_addr(struct ntb_dev *ntb, int pidx, int sidx, ndev->peer_reg->spad); } -static u32 intel_ntb_peer_spad_read(struct ntb_dev *ntb, int pidx, int sidx) +u32 intel_ntb_peer_spad_read(struct ntb_dev *ntb, int pidx, int sidx) { struct intel_ntb_dev *ndev = ntb_ndev(ntb); @@ -1413,8 +1179,8 @@ static u32 intel_ntb_peer_spad_read(struct ntb_dev *ntb, int pidx, int sidx) ndev->peer_reg->spad); } -static int intel_ntb_peer_spad_write(struct ntb_dev *ntb, int pidx, - int sidx, u32 val) +int intel_ntb_peer_spad_write(struct ntb_dev *ntb, int pidx, int sidx, + u32 val) { struct intel_ntb_dev *ndev = ntb_ndev(ntb); @@ -1423,336 +1189,6 @@ static int intel_ntb_peer_spad_write(struct ntb_dev *ntb, int pidx, ndev->peer_reg->spad); } -/* Skylake Xeon NTB */ - -static int skx_poll_link(struct intel_ntb_dev *ndev) -{ - u16 reg_val; - int rc; - - ndev->reg->db_iowrite(ndev->db_link_mask, - ndev->self_mmio + - ndev->self_reg->db_clear); - - rc = pci_read_config_word(ndev->ntb.pdev, - SKX_LINK_STATUS_OFFSET, ®_val); - if (rc) - return 0; - - if (reg_val == ndev->lnk_sta) - return 0; - - ndev->lnk_sta = reg_val; - - return 1; -} - -static u64 skx_db_ioread(void __iomem *mmio) -{ - return ioread64(mmio); -} - -static void skx_db_iowrite(u64 bits, void __iomem *mmio) -{ - iowrite64(bits, mmio); -} - -static int skx_init_isr(struct intel_ntb_dev *ndev) -{ - int i; - - /* - * The MSIX vectors and the interrupt status bits are not lined up - * on Skylake. By default the link status bit is bit 32, however it - * is by default MSIX vector0. We need to fixup to line them up. - * The vectors at reset is 1-32,0. We need to reprogram to 0-32. - */ - - for (i = 0; i < SKX_DB_MSIX_VECTOR_COUNT; i++) - iowrite8(i, ndev->self_mmio + SKX_INTVEC_OFFSET + i); - - /* move link status down one as workaround */ - if (ndev->hwerr_flags & NTB_HWERR_MSIX_VECTOR32_BAD) { - iowrite8(SKX_DB_MSIX_VECTOR_COUNT - 2, - ndev->self_mmio + SKX_INTVEC_OFFSET + - (SKX_DB_MSIX_VECTOR_COUNT - 1)); - } - - return ndev_init_isr(ndev, SKX_DB_MSIX_VECTOR_COUNT, - SKX_DB_MSIX_VECTOR_COUNT, - SKX_DB_MSIX_VECTOR_SHIFT, - SKX_DB_TOTAL_SHIFT); -} - -static int skx_setup_b2b_mw(struct intel_ntb_dev *ndev, - const struct intel_b2b_addr *addr, - const struct intel_b2b_addr *peer_addr) -{ - struct pci_dev *pdev; - void __iomem *mmio; - phys_addr_t bar_addr; - - pdev = ndev->ntb.pdev; - mmio = ndev->self_mmio; - - /* setup incoming bar limits == base addrs (zero length windows) */ - bar_addr = addr->bar2_addr64; - iowrite64(bar_addr, mmio + SKX_IMBAR1XLMT_OFFSET); - bar_addr = ioread64(mmio + SKX_IMBAR1XLMT_OFFSET); - dev_dbg(&pdev->dev, "IMBAR1XLMT %#018llx\n", bar_addr); - - bar_addr = addr->bar4_addr64; - iowrite64(bar_addr, mmio + SKX_IMBAR2XLMT_OFFSET); - bar_addr = ioread64(mmio + SKX_IMBAR2XLMT_OFFSET); - dev_dbg(&pdev->dev, "IMBAR2XLMT %#018llx\n", bar_addr); - - /* zero incoming translation addrs */ - iowrite64(0, mmio + SKX_IMBAR1XBASE_OFFSET); - iowrite64(0, mmio + SKX_IMBAR2XBASE_OFFSET); - - ndev->peer_mmio = ndev->self_mmio; - - return 0; -} - -static int skx_init_ntb(struct intel_ntb_dev *ndev) -{ - int rc; - - - ndev->mw_count = XEON_MW_COUNT; - ndev->spad_count = SKX_SPAD_COUNT; - ndev->db_count = SKX_DB_COUNT; - ndev->db_link_mask = SKX_DB_LINK_BIT; - - /* DB fixup for using 31 right now */ - if (ndev->hwerr_flags & NTB_HWERR_MSIX_VECTOR32_BAD) - ndev->db_link_mask |= BIT_ULL(31); - - switch (ndev->ntb.topo) { - case NTB_TOPO_B2B_USD: - case NTB_TOPO_B2B_DSD: - ndev->self_reg = &skx_pri_reg; - ndev->peer_reg = &skx_b2b_reg; - ndev->xlat_reg = &skx_sec_xlat; - - if (ndev->ntb.topo == NTB_TOPO_B2B_USD) { - rc = skx_setup_b2b_mw(ndev, - &xeon_b2b_dsd_addr, - &xeon_b2b_usd_addr); - } else { - rc = skx_setup_b2b_mw(ndev, - &xeon_b2b_usd_addr, - &xeon_b2b_dsd_addr); - } - - if (rc) - return rc; - - /* Enable Bus Master and Memory Space on the secondary side */ - iowrite16(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER, - ndev->self_mmio + SKX_SPCICMD_OFFSET); - - break; - - default: - return -EINVAL; - } - - ndev->db_valid_mask = BIT_ULL(ndev->db_count) - 1; - - ndev->reg->db_iowrite(ndev->db_valid_mask, - ndev->self_mmio + - ndev->self_reg->db_mask); - - return 0; -} - -static int skx_init_dev(struct intel_ntb_dev *ndev) -{ - struct pci_dev *pdev; - u8 ppd; - int rc; - - pdev = ndev->ntb.pdev; - - ndev->reg = &skx_reg; - - rc = pci_read_config_byte(pdev, XEON_PPD_OFFSET, &ppd); - if (rc) - return -EIO; - - ndev->ntb.topo = xeon_ppd_topo(ndev, ppd); - dev_dbg(&pdev->dev, "ppd %#x topo %s\n", ppd, - ntb_topo_string(ndev->ntb.topo)); - if (ndev->ntb.topo == NTB_TOPO_NONE) - return -EINVAL; - - if (pdev_is_skx_xeon(pdev)) - ndev->hwerr_flags |= NTB_HWERR_MSIX_VECTOR32_BAD; - - rc = skx_init_ntb(ndev); - if (rc) - return rc; - - return skx_init_isr(ndev); -} - -static int intel_ntb3_link_enable(struct ntb_dev *ntb, - enum ntb_speed max_speed, - enum ntb_width max_width) -{ - struct intel_ntb_dev *ndev; - u32 ntb_ctl; - - ndev = container_of(ntb, struct intel_ntb_dev, ntb); - - dev_dbg(&ntb->pdev->dev, - "Enabling link with max_speed %d max_width %d\n", - max_speed, max_width); - - if (max_speed != NTB_SPEED_AUTO) - dev_dbg(&ntb->pdev->dev, "ignoring max_speed %d\n", max_speed); - if (max_width != NTB_WIDTH_AUTO) - dev_dbg(&ntb->pdev->dev, "ignoring max_width %d\n", max_width); - - ntb_ctl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl); - ntb_ctl &= ~(NTB_CTL_DISABLE | NTB_CTL_CFG_LOCK); - ntb_ctl |= NTB_CTL_P2S_BAR2_SNOOP | NTB_CTL_S2P_BAR2_SNOOP; - ntb_ctl |= NTB_CTL_P2S_BAR4_SNOOP | NTB_CTL_S2P_BAR4_SNOOP; - iowrite32(ntb_ctl, ndev->self_mmio + ndev->reg->ntb_ctl); - - return 0; -} -static int intel_ntb3_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx, - dma_addr_t addr, resource_size_t size) -{ - struct intel_ntb_dev *ndev = ntb_ndev(ntb); - unsigned long xlat_reg, limit_reg; - resource_size_t bar_size, mw_size; - void __iomem *mmio; - u64 base, limit, reg_val; - int bar; - - if (pidx != NTB_DEF_PEER_IDX) - return -EINVAL; - - if (idx >= ndev->b2b_idx && !ndev->b2b_off) - idx += 1; - - bar = ndev_mw_to_bar(ndev, idx); - if (bar < 0) - return bar; - - bar_size = pci_resource_len(ndev->ntb.pdev, bar); - - if (idx == ndev->b2b_idx) - mw_size = bar_size - ndev->b2b_off; - else - mw_size = bar_size; - - /* hardware requires that addr is aligned to bar size */ - if (addr & (bar_size - 1)) - return -EINVAL; - - /* make sure the range fits in the usable mw size */ - if (size > mw_size) - return -EINVAL; - - mmio = ndev->self_mmio; - xlat_reg = ndev->xlat_reg->bar2_xlat + (idx * 0x10); - limit_reg = ndev->xlat_reg->bar2_limit + (idx * 0x10); - base = pci_resource_start(ndev->ntb.pdev, bar); - - /* Set the limit if supported, if size is not mw_size */ - if (limit_reg && size != mw_size) - limit = base + size; - else - limit = base + mw_size; - - /* set and verify setting the translation address */ - iowrite64(addr, mmio + xlat_reg); - reg_val = ioread64(mmio + xlat_reg); - if (reg_val != addr) { - iowrite64(0, mmio + xlat_reg); - return -EIO; - } - - dev_dbg(&ntb->pdev->dev, "BAR %d IMBARXBASE: %#Lx\n", bar, reg_val); - - /* set and verify setting the limit */ - iowrite64(limit, mmio + limit_reg); - reg_val = ioread64(mmio + limit_reg); - if (reg_val != limit) { - iowrite64(base, mmio + limit_reg); - iowrite64(0, mmio + xlat_reg); - return -EIO; - } - - dev_dbg(&ntb->pdev->dev, "BAR %d IMBARXLMT: %#Lx\n", bar, reg_val); - - /* setup the EP */ - limit_reg = ndev->xlat_reg->bar2_limit + (idx * 0x10) + 0x4000; - base = ioread64(mmio + SKX_EMBAR1_OFFSET + (8 * idx)); - base &= ~0xf; - - if (limit_reg && size != mw_size) - limit = base + size; - else - limit = base + mw_size; - - /* set and verify setting the limit */ - iowrite64(limit, mmio + limit_reg); - reg_val = ioread64(mmio + limit_reg); - if (reg_val != limit) { - iowrite64(base, mmio + limit_reg); - iowrite64(0, mmio + xlat_reg); - return -EIO; - } - - dev_dbg(&ntb->pdev->dev, "BAR %d EMBARXLMT: %#Lx\n", bar, reg_val); - - return 0; -} - -static int intel_ntb3_peer_db_set(struct ntb_dev *ntb, u64 db_bits) -{ - struct intel_ntb_dev *ndev = ntb_ndev(ntb); - int bit; - - if (db_bits & ~ndev->db_valid_mask) - return -EINVAL; - - while (db_bits) { - bit = __ffs(db_bits); - iowrite32(1, ndev->peer_mmio + - ndev->peer_reg->db_bell + (bit * 4)); - db_bits &= db_bits - 1; - } - - return 0; -} - -static u64 intel_ntb3_db_read(struct ntb_dev *ntb) -{ - struct intel_ntb_dev *ndev = ntb_ndev(ntb); - - return ndev_db_read(ndev, - ndev->self_mmio + - ndev->self_reg->db_clear); -} - -static int intel_ntb3_db_clear(struct ntb_dev *ntb, u64 db_bits) -{ - struct intel_ntb_dev *ndev = ntb_ndev(ntb); - - return ndev_db_write(ndev, db_bits, - ndev->self_mmio + - ndev->self_reg->db_clear); -} - -/* XEON */ - static u64 xeon_db_ioread(void __iomem *mmio) { return (u64)ioread16(mmio); @@ -1785,7 +1221,7 @@ static int xeon_poll_link(struct intel_ntb_dev *ndev) return 1; } -static int xeon_link_is_up(struct intel_ntb_dev *ndev) +int xeon_link_is_up(struct intel_ntb_dev *ndev) { if (ndev->ntb.topo == NTB_TOPO_SEC) return 1; @@ -1793,7 +1229,7 @@ static int xeon_link_is_up(struct intel_ntb_dev *ndev) return NTB_LNK_STA_ACTIVE(ndev->lnk_sta); } -static inline enum ntb_topo xeon_ppd_topo(struct intel_ntb_dev *ndev, u8 ppd) +enum ntb_topo xeon_ppd_topo(struct intel_ntb_dev *ndev, u8 ppd) { switch (ppd & XEON_PPD_TOPO_MASK) { case XEON_PPD_TOPO_B2B_USD: @@ -2410,7 +1846,7 @@ static int intel_ntb_pci_probe(struct pci_dev *pdev, node = dev_to_node(&pdev->dev); - if (pdev_is_xeon(pdev)) { + if (pdev_is_gen1(pdev)) { ndev = kzalloc_node(sizeof(*ndev), GFP_KERNEL, node); if (!ndev) { rc = -ENOMEM; @@ -2427,7 +1863,7 @@ static int intel_ntb_pci_probe(struct pci_dev *pdev, if (rc) goto err_init_dev; - } else if (pdev_is_skx_xeon(pdev)) { + } else if (pdev_is_gen3(pdev)) { ndev = kzalloc_node(sizeof(*ndev), GFP_KERNEL, node); if (!ndev) { rc = -ENOMEM; @@ -2441,7 +1877,7 @@ static int intel_ntb_pci_probe(struct pci_dev *pdev, if (rc) goto err_init_pci; - rc = skx_init_dev(ndev); + rc = gen3_init_dev(ndev); if (rc) goto err_init_dev; @@ -2466,7 +1902,7 @@ static int intel_ntb_pci_probe(struct pci_dev *pdev, err_register: ndev_deinit_debugfs(ndev); - if (pdev_is_xeon(pdev) || pdev_is_skx_xeon(pdev)) + if (pdev_is_gen1(pdev) || pdev_is_gen3(pdev)) xeon_deinit_dev(ndev); err_init_dev: intel_ntb_deinit_pci(ndev); @@ -2482,7 +1918,7 @@ static void intel_ntb_pci_remove(struct pci_dev *pdev) ntb_unregister_device(&ndev->ntb); ndev_deinit_debugfs(ndev); - if (pdev_is_xeon(pdev) || pdev_is_skx_xeon(pdev)) + if (pdev_is_gen1(pdev) || pdev_is_gen3(pdev)) xeon_deinit_dev(ndev); intel_ntb_deinit_pci(ndev); kfree(ndev); @@ -2537,50 +1973,20 @@ static const struct intel_ntb_xlat_reg xeon_sec_xlat = { .bar2_xlat = XEON_SBAR23XLAT_OFFSET, }; -static struct intel_b2b_addr xeon_b2b_usd_addr = { +struct intel_b2b_addr xeon_b2b_usd_addr = { .bar2_addr64 = XEON_B2B_BAR2_ADDR64, .bar4_addr64 = XEON_B2B_BAR4_ADDR64, .bar4_addr32 = XEON_B2B_BAR4_ADDR32, .bar5_addr32 = XEON_B2B_BAR5_ADDR32, }; -static struct intel_b2b_addr xeon_b2b_dsd_addr = { +struct intel_b2b_addr xeon_b2b_dsd_addr = { .bar2_addr64 = XEON_B2B_BAR2_ADDR64, .bar4_addr64 = XEON_B2B_BAR4_ADDR64, .bar4_addr32 = XEON_B2B_BAR4_ADDR32, .bar5_addr32 = XEON_B2B_BAR5_ADDR32, }; -static const struct intel_ntb_reg skx_reg = { - .poll_link = skx_poll_link, - .link_is_up = xeon_link_is_up, - .db_ioread = skx_db_ioread, - .db_iowrite = skx_db_iowrite, - .db_size = sizeof(u32), - .ntb_ctl = SKX_NTBCNTL_OFFSET, - .mw_bar = {2, 4}, -}; - -static const struct intel_ntb_alt_reg skx_pri_reg = { - .db_bell = SKX_EM_DOORBELL_OFFSET, - .db_clear = SKX_IM_INT_STATUS_OFFSET, - .db_mask = SKX_IM_INT_DISABLE_OFFSET, - .spad = SKX_IM_SPAD_OFFSET, -}; - -static const struct intel_ntb_alt_reg skx_b2b_reg = { - .db_bell = SKX_IM_DOORBELL_OFFSET, - .db_clear = SKX_EM_INT_STATUS_OFFSET, - .db_mask = SKX_EM_INT_DISABLE_OFFSET, - .spad = SKX_B2B_SPAD_OFFSET, -}; - -static const struct intel_ntb_xlat_reg skx_sec_xlat = { -/* .bar0_base = SKX_EMBAR0_OFFSET, */ - .bar2_limit = SKX_IMBAR1XLMT_OFFSET, - .bar2_xlat = SKX_IMBAR1XBASE_OFFSET, -}; - /* operations for primary side of local ntb */ static const struct ntb_dev_ops intel_ntb_ops = { .mw_count = intel_ntb_mw_count, @@ -2610,33 +2016,6 @@ static const struct ntb_dev_ops intel_ntb_ops = { .peer_spad_write = intel_ntb_peer_spad_write, }; -static const struct ntb_dev_ops intel_ntb3_ops = { - .mw_count = intel_ntb_mw_count, - .mw_get_align = intel_ntb_mw_get_align, - .mw_set_trans = intel_ntb3_mw_set_trans, - .peer_mw_count = intel_ntb_peer_mw_count, - .peer_mw_get_addr = intel_ntb_peer_mw_get_addr, - .link_is_up = intel_ntb_link_is_up, - .link_enable = intel_ntb3_link_enable, - .link_disable = intel_ntb_link_disable, - .db_valid_mask = intel_ntb_db_valid_mask, - .db_vector_count = intel_ntb_db_vector_count, - .db_vector_mask = intel_ntb_db_vector_mask, - .db_read = intel_ntb3_db_read, - .db_clear = intel_ntb3_db_clear, - .db_set_mask = intel_ntb_db_set_mask, - .db_clear_mask = intel_ntb_db_clear_mask, - .peer_db_addr = intel_ntb_peer_db_addr, - .peer_db_set = intel_ntb3_peer_db_set, - .spad_is_unsafe = intel_ntb_spad_is_unsafe, - .spad_count = intel_ntb_spad_count, - .spad_read = intel_ntb_spad_read, - .spad_write = intel_ntb_spad_write, - .peer_spad_addr = intel_ntb_peer_spad_addr, - .peer_spad_read = intel_ntb_peer_spad_read, - .peer_spad_write = intel_ntb_peer_spad_write, -}; - static const struct file_operations intel_ntb_debugfs_info = { .owner = THIS_MODULE, .open = simple_open, diff --git a/drivers/ntb/hw/intel/ntb_hw_gen1.h b/drivers/ntb/hw/intel/ntb_hw_gen1.h new file mode 100644 index 000000000000..ad8ec1444436 --- /dev/null +++ b/drivers/ntb/hw/intel/ntb_hw_gen1.h @@ -0,0 +1,182 @@ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2012-2017 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * BSD LICENSE + * + * Copyright(c) 2012-2017 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copy + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _NTB_INTEL_GEN1_H_ +#define _NTB_INTEL_GEN1_H_ + +#include "ntb_hw_intel.h" + +/* Intel Gen1 Xeon hardware */ +#define XEON_PBAR23LMT_OFFSET 0x0000 +#define XEON_PBAR45LMT_OFFSET 0x0008 +#define XEON_PBAR4LMT_OFFSET 0x0008 +#define XEON_PBAR5LMT_OFFSET 0x000c +#define XEON_PBAR23XLAT_OFFSET 0x0010 +#define XEON_PBAR45XLAT_OFFSET 0x0018 +#define XEON_PBAR4XLAT_OFFSET 0x0018 +#define XEON_PBAR5XLAT_OFFSET 0x001c +#define XEON_SBAR23LMT_OFFSET 0x0020 +#define XEON_SBAR45LMT_OFFSET 0x0028 +#define XEON_SBAR4LMT_OFFSET 0x0028 +#define XEON_SBAR5LMT_OFFSET 0x002c +#define XEON_SBAR23XLAT_OFFSET 0x0030 +#define XEON_SBAR45XLAT_OFFSET 0x0038 +#define XEON_SBAR4XLAT_OFFSET 0x0038 +#define XEON_SBAR5XLAT_OFFSET 0x003c +#define XEON_SBAR0BASE_OFFSET 0x0040 +#define XEON_SBAR23BASE_OFFSET 0x0048 +#define XEON_SBAR45BASE_OFFSET 0x0050 +#define XEON_SBAR4BASE_OFFSET 0x0050 +#define XEON_SBAR5BASE_OFFSET 0x0054 +#define XEON_SBDF_OFFSET 0x005c +#define XEON_NTBCNTL_OFFSET 0x0058 +#define XEON_PDOORBELL_OFFSET 0x0060 +#define XEON_PDBMSK_OFFSET 0x0062 +#define XEON_SDOORBELL_OFFSET 0x0064 +#define XEON_SDBMSK_OFFSET 0x0066 +#define XEON_USMEMMISS_OFFSET 0x0070 +#define XEON_SPAD_OFFSET 0x0080 +#define XEON_PBAR23SZ_OFFSET 0x00d0 +#define XEON_PBAR45SZ_OFFSET 0x00d1 +#define XEON_PBAR4SZ_OFFSET 0x00d1 +#define XEON_SBAR23SZ_OFFSET 0x00d2 +#define XEON_SBAR45SZ_OFFSET 0x00d3 +#define XEON_SBAR4SZ_OFFSET 0x00d3 +#define XEON_PPD_OFFSET 0x00d4 +#define XEON_PBAR5SZ_OFFSET 0x00d5 +#define XEON_SBAR5SZ_OFFSET 0x00d6 +#define XEON_WCCNTRL_OFFSET 0x00e0 +#define XEON_UNCERRSTS_OFFSET 0x014c +#define XEON_CORERRSTS_OFFSET 0x0158 +#define XEON_LINK_STATUS_OFFSET 0x01a2 +#define XEON_SPCICMD_OFFSET 0x0504 +#define XEON_DEVCTRL_OFFSET 0x0598 +#define XEON_DEVSTS_OFFSET 0x059a +#define XEON_SLINK_STATUS_OFFSET 0x05a2 +#define XEON_B2B_SPAD_OFFSET 0x0100 +#define XEON_B2B_DOORBELL_OFFSET 0x0140 +#define XEON_B2B_XLAT_OFFSETL 0x0144 +#define XEON_B2B_XLAT_OFFSETU 0x0148 +#define XEON_PPD_CONN_MASK 0x03 +#define XEON_PPD_CONN_TRANSPARENT 0x00 +#define XEON_PPD_CONN_B2B 0x01 +#define XEON_PPD_CONN_RP 0x02 +#define XEON_PPD_DEV_MASK 0x10 +#define XEON_PPD_DEV_USD 0x00 +#define XEON_PPD_DEV_DSD 0x10 +#define XEON_PPD_SPLIT_BAR_MASK 0x40 + +#define XEON_PPD_TOPO_MASK (XEON_PPD_CONN_MASK | XEON_PPD_DEV_MASK) +#define XEON_PPD_TOPO_PRI_USD (XEON_PPD_CONN_RP | XEON_PPD_DEV_USD) +#define XEON_PPD_TOPO_PRI_DSD (XEON_PPD_CONN_RP | XEON_PPD_DEV_DSD) +#define XEON_PPD_TOPO_SEC_USD (XEON_PPD_CONN_TRANSPARENT | XEON_PPD_DEV_USD) +#define XEON_PPD_TOPO_SEC_DSD (XEON_PPD_CONN_TRANSPARENT | XEON_PPD_DEV_DSD) +#define XEON_PPD_TOPO_B2B_USD (XEON_PPD_CONN_B2B | XEON_PPD_DEV_USD) +#define XEON_PPD_TOPO_B2B_DSD (XEON_PPD_CONN_B2B | XEON_PPD_DEV_DSD) + +#define XEON_MW_COUNT 2 +#define HSX_SPLIT_BAR_MW_COUNT 3 +#define XEON_DB_COUNT 15 +#define XEON_DB_LINK 15 +#define XEON_DB_LINK_BIT BIT_ULL(XEON_DB_LINK) +#define XEON_DB_MSIX_VECTOR_COUNT 4 +#define XEON_DB_MSIX_VECTOR_SHIFT 5 +#define XEON_DB_TOTAL_SHIFT 16 +#define XEON_SPAD_COUNT 16 + +/* Use the following addresses for translation between b2b ntb devices in case + * the hardware default values are not reliable. */ +#define XEON_B2B_BAR0_ADDR 0x1000000000000000ull +#define XEON_B2B_BAR2_ADDR64 0x2000000000000000ull +#define XEON_B2B_BAR4_ADDR64 0x4000000000000000ull +#define XEON_B2B_BAR4_ADDR32 0x20000000u +#define XEON_B2B_BAR5_ADDR32 0x40000000u + +/* The peer ntb secondary config space is 32KB fixed size */ +#define XEON_B2B_MIN_SIZE 0x8000 + +/* flags to indicate hardware errata */ +#define NTB_HWERR_SDOORBELL_LOCKUP BIT_ULL(0) +#define NTB_HWERR_SB01BASE_LOCKUP BIT_ULL(1) +#define NTB_HWERR_B2BDOORBELL_BIT14 BIT_ULL(2) +#define NTB_HWERR_MSIX_VECTOR32_BAD BIT_ULL(3) + +extern struct intel_b2b_addr xeon_b2b_usd_addr; +extern struct intel_b2b_addr xeon_b2b_dsd_addr; + +int ndev_init_isr(struct intel_ntb_dev *ndev, int msix_min, int msix_max, + int msix_shift, int total_shift); +enum ntb_topo xeon_ppd_topo(struct intel_ntb_dev *ndev, u8 ppd); +u64 ndev_db_read(struct intel_ntb_dev *ndev, void __iomem *mmio); +int ndev_db_write(struct intel_ntb_dev *ndev, u64 db_bits, + void __iomem *mmio); +int ndev_mw_to_bar(struct intel_ntb_dev *ndev, int idx); +int intel_ntb_mw_count(struct ntb_dev *ntb, int pidx); +int intel_ntb_mw_get_align(struct ntb_dev *ntb, int pidx, int idx, + resource_size_t *addr_align, resource_size_t *size_align, + resource_size_t *size_max); +int intel_ntb_peer_mw_count(struct ntb_dev *ntb); +int intel_ntb_peer_mw_get_addr(struct ntb_dev *ntb, int idx, + phys_addr_t *base, resource_size_t *size); +u64 intel_ntb_link_is_up(struct ntb_dev *ntb, enum ntb_speed *speed, + enum ntb_width *width); +int intel_ntb_link_disable(struct ntb_dev *ntb); +u64 intel_ntb_db_valid_mask(struct ntb_dev *ntb); +int intel_ntb_db_vector_count(struct ntb_dev *ntb); +u64 intel_ntb_db_vector_mask(struct ntb_dev *ntb, int db_vector); +int intel_ntb_db_set_mask(struct ntb_dev *ntb, u64 db_bits); +int intel_ntb_db_clear_mask(struct ntb_dev *ntb, u64 db_bits); +int intel_ntb_peer_db_addr(struct ntb_dev *ntb, phys_addr_t *db_addr, + resource_size_t *db_size); +int intel_ntb_spad_is_unsafe(struct ntb_dev *ntb); +int intel_ntb_spad_count(struct ntb_dev *ntb); +u32 intel_ntb_spad_read(struct ntb_dev *ntb, int idx); +int intel_ntb_spad_write(struct ntb_dev *ntb, int idx, u32 val); +u32 intel_ntb_peer_spad_read(struct ntb_dev *ntb, int pidx, int sidx); +int intel_ntb_peer_spad_write(struct ntb_dev *ntb, int pidx, int sidx, + u32 val); +int intel_ntb_peer_spad_addr(struct ntb_dev *ntb, int pidx, int sidx, + phys_addr_t *spad_addr); +int xeon_link_is_up(struct intel_ntb_dev *ndev); + +#endif diff --git a/drivers/ntb/hw/intel/ntb_hw_gen3.c b/drivers/ntb/hw/intel/ntb_hw_gen3.c new file mode 100644 index 000000000000..b3fa24778f94 --- /dev/null +++ b/drivers/ntb/hw/intel/ntb_hw_gen3.c @@ -0,0 +1,597 @@ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2017 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * BSD LICENSE + * + * Copyright(c) 2017 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copy + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Intel PCIe GEN3 NTB Linux driver + * + */ + +#include <linux/debugfs.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/random.h> +#include <linux/slab.h> +#include <linux/ntb.h> + +#include "ntb_hw_intel.h" +#include "ntb_hw_gen1.h" +#include "ntb_hw_gen3.h" + +static int gen3_poll_link(struct intel_ntb_dev *ndev); + +static const struct intel_ntb_reg gen3_reg = { + .poll_link = gen3_poll_link, + .link_is_up = xeon_link_is_up, + .db_ioread = gen3_db_ioread, + .db_iowrite = gen3_db_iowrite, + .db_size = sizeof(u32), + .ntb_ctl = GEN3_NTBCNTL_OFFSET, + .mw_bar = {2, 4}, +}; + +static const struct intel_ntb_alt_reg gen3_pri_reg = { + .db_bell = GEN3_EM_DOORBELL_OFFSET, + .db_clear = GEN3_IM_INT_STATUS_OFFSET, + .db_mask = GEN3_IM_INT_DISABLE_OFFSET, + .spad = GEN3_IM_SPAD_OFFSET, +}; + +static const struct intel_ntb_alt_reg gen3_b2b_reg = { + .db_bell = GEN3_IM_DOORBELL_OFFSET, + .db_clear = GEN3_EM_INT_STATUS_OFFSET, + .db_mask = GEN3_EM_INT_DISABLE_OFFSET, + .spad = GEN3_B2B_SPAD_OFFSET, +}; + +static const struct intel_ntb_xlat_reg gen3_sec_xlat = { +/* .bar0_base = GEN3_EMBAR0_OFFSET, */ + .bar2_limit = GEN3_IMBAR1XLMT_OFFSET, + .bar2_xlat = GEN3_IMBAR1XBASE_OFFSET, +}; + +static int gen3_poll_link(struct intel_ntb_dev *ndev) +{ + u16 reg_val; + int rc; + + ndev->reg->db_iowrite(ndev->db_link_mask, + ndev->self_mmio + + ndev->self_reg->db_clear); + + rc = pci_read_config_word(ndev->ntb.pdev, + GEN3_LINK_STATUS_OFFSET, ®_val); + if (rc) + return 0; + + if (reg_val == ndev->lnk_sta) + return 0; + + ndev->lnk_sta = reg_val; + + return 1; +} + +static int gen3_init_isr(struct intel_ntb_dev *ndev) +{ + int i; + + /* + * The MSIX vectors and the interrupt status bits are not lined up + * on Skylake. By default the link status bit is bit 32, however it + * is by default MSIX vector0. We need to fixup to line them up. + * The vectors at reset is 1-32,0. We need to reprogram to 0-32. + */ + + for (i = 0; i < GEN3_DB_MSIX_VECTOR_COUNT; i++) + iowrite8(i, ndev->self_mmio + GEN3_INTVEC_OFFSET + i); + + /* move link status down one as workaround */ + if (ndev->hwerr_flags & NTB_HWERR_MSIX_VECTOR32_BAD) { + iowrite8(GEN3_DB_MSIX_VECTOR_COUNT - 2, + ndev->self_mmio + GEN3_INTVEC_OFFSET + + (GEN3_DB_MSIX_VECTOR_COUNT - 1)); + } + + return ndev_init_isr(ndev, GEN3_DB_MSIX_VECTOR_COUNT, + GEN3_DB_MSIX_VECTOR_COUNT, + GEN3_DB_MSIX_VECTOR_SHIFT, + GEN3_DB_TOTAL_SHIFT); +} + +static int gen3_setup_b2b_mw(struct intel_ntb_dev *ndev, + const struct intel_b2b_addr *addr, + const struct intel_b2b_addr *peer_addr) +{ + struct pci_dev *pdev; + void __iomem *mmio; + phys_addr_t bar_addr; + + pdev = ndev->ntb.pdev; + mmio = ndev->self_mmio; + + /* setup incoming bar limits == base addrs (zero length windows) */ + bar_addr = addr->bar2_addr64; + iowrite64(bar_addr, mmio + GEN3_IMBAR1XLMT_OFFSET); + bar_addr = ioread64(mmio + GEN3_IMBAR1XLMT_OFFSET); + dev_dbg(&pdev->dev, "IMBAR1XLMT %#018llx\n", bar_addr); + + bar_addr = addr->bar4_addr64; + iowrite64(bar_addr, mmio + GEN3_IMBAR2XLMT_OFFSET); + bar_addr = ioread64(mmio + GEN3_IMBAR2XLMT_OFFSET); + dev_dbg(&pdev->dev, "IMBAR2XLMT %#018llx\n", bar_addr); + + /* zero incoming translation addrs */ + iowrite64(0, mmio + GEN3_IMBAR1XBASE_OFFSET); + iowrite64(0, mmio + GEN3_IMBAR2XBASE_OFFSET); + + ndev->peer_mmio = ndev->self_mmio; + + return 0; +} + +static int gen3_init_ntb(struct intel_ntb_dev *ndev) +{ + int rc; + + + ndev->mw_count = XEON_MW_COUNT; + ndev->spad_count = GEN3_SPAD_COUNT; + ndev->db_count = GEN3_DB_COUNT; + ndev->db_link_mask = GEN3_DB_LINK_BIT; + + /* DB fixup for using 31 right now */ + if (ndev->hwerr_flags & NTB_HWERR_MSIX_VECTOR32_BAD) + ndev->db_link_mask |= BIT_ULL(31); + + switch (ndev->ntb.topo) { + case NTB_TOPO_B2B_USD: + case NTB_TOPO_B2B_DSD: + ndev->self_reg = &gen3_pri_reg; + ndev->peer_reg = &gen3_b2b_reg; + ndev->xlat_reg = &gen3_sec_xlat; + + if (ndev->ntb.topo == NTB_TOPO_B2B_USD) { + rc = gen3_setup_b2b_mw(ndev, + &xeon_b2b_dsd_addr, + &xeon_b2b_usd_addr); + } else { + rc = gen3_setup_b2b_mw(ndev, + &xeon_b2b_usd_addr, + &xeon_b2b_dsd_addr); + } + + if (rc) + return rc; + + /* Enable Bus Master and Memory Space on the secondary side */ + iowrite16(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER, + ndev->self_mmio + GEN3_SPCICMD_OFFSET); + + break; + + default: + return -EINVAL; + } + + ndev->db_valid_mask = BIT_ULL(ndev->db_count) - 1; + + ndev->reg->db_iowrite(ndev->db_valid_mask, + ndev->self_mmio + + ndev->self_reg->db_mask); + + return 0; +} + +int gen3_init_dev(struct intel_ntb_dev *ndev) +{ + struct pci_dev *pdev; + u8 ppd; + int rc; + + pdev = ndev->ntb.pdev; + + ndev->reg = &gen3_reg; + + rc = pci_read_config_byte(pdev, XEON_PPD_OFFSET, &ppd); + if (rc) + return -EIO; + + ndev->ntb.topo = xeon_ppd_topo(ndev, ppd); + dev_dbg(&pdev->dev, "ppd %#x topo %s\n", ppd, + ntb_topo_string(ndev->ntb.topo)); + if (ndev->ntb.topo == NTB_TOPO_NONE) + return -EINVAL; + + ndev->hwerr_flags |= NTB_HWERR_MSIX_VECTOR32_BAD; + + rc = gen3_init_ntb(ndev); + if (rc) + return rc; + + return gen3_init_isr(ndev); +} + +ssize_t ndev_ntb3_debugfs_read(struct file *filp, char __user *ubuf, + size_t count, loff_t *offp) +{ + struct intel_ntb_dev *ndev; + void __iomem *mmio; + char *buf; + size_t buf_size; + ssize_t ret, off; + union { u64 v64; u32 v32; u16 v16; } u; + + ndev = filp->private_data; + mmio = ndev->self_mmio; + + buf_size = min(count, 0x800ul); + + buf = kmalloc(buf_size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + off = 0; + + off += scnprintf(buf + off, buf_size - off, + "NTB Device Information:\n"); + + off += scnprintf(buf + off, buf_size - off, + "Connection Topology -\t%s\n", + ntb_topo_string(ndev->ntb.topo)); + + off += scnprintf(buf + off, buf_size - off, + "NTB CTL -\t\t%#06x\n", ndev->ntb_ctl); + off += scnprintf(buf + off, buf_size - off, + "LNK STA -\t\t%#06x\n", ndev->lnk_sta); + + if (!ndev->reg->link_is_up(ndev)) + off += scnprintf(buf + off, buf_size - off, + "Link Status -\t\tDown\n"); + else { + off += scnprintf(buf + off, buf_size - off, + "Link Status -\t\tUp\n"); + off += scnprintf(buf + off, buf_size - off, + "Link Speed -\t\tPCI-E Gen %u\n", + NTB_LNK_STA_SPEED(ndev->lnk_sta)); + off += scnprintf(buf + off, buf_size - off, + "Link Width -\t\tx%u\n", + NTB_LNK_STA_WIDTH(ndev->lnk_sta)); + } + + off += scnprintf(buf + off, buf_size - off, + "Memory Window Count -\t%u\n", ndev->mw_count); + off += scnprintf(buf + off, buf_size - off, + "Scratchpad Count -\t%u\n", ndev->spad_count); + off += scnprintf(buf + off, buf_size - off, + "Doorbell Count -\t%u\n", ndev->db_count); + off += scnprintf(buf + off, buf_size - off, + "Doorbell Vector Count -\t%u\n", ndev->db_vec_count); + off += scnprintf(buf + off, buf_size - off, + "Doorbell Vector Shift -\t%u\n", ndev->db_vec_shift); + + off += scnprintf(buf + off, buf_size - off, + "Doorbell Valid Mask -\t%#llx\n", ndev->db_valid_mask); + off += scnprintf(buf + off, buf_size - off, + "Doorbell Link Mask -\t%#llx\n", ndev->db_link_mask); + off += scnprintf(buf + off, buf_size - off, + "Doorbell Mask Cached -\t%#llx\n", ndev->db_mask); + + u.v64 = ndev_db_read(ndev, mmio + ndev->self_reg->db_mask); + off += scnprintf(buf + off, buf_size - off, + "Doorbell Mask -\t\t%#llx\n", u.v64); + + u.v64 = ndev_db_read(ndev, mmio + ndev->self_reg->db_bell); + off += scnprintf(buf + off, buf_size - off, + "Doorbell Bell -\t\t%#llx\n", u.v64); + + off += scnprintf(buf + off, buf_size - off, + "\nNTB Incoming XLAT:\n"); + + u.v64 = ioread64(mmio + GEN3_IMBAR1XBASE_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "IMBAR1XBASE -\t\t%#018llx\n", u.v64); + + u.v64 = ioread64(mmio + GEN3_IMBAR2XBASE_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "IMBAR2XBASE -\t\t%#018llx\n", u.v64); + + u.v64 = ioread64(mmio + GEN3_IMBAR1XLMT_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "IMBAR1XLMT -\t\t\t%#018llx\n", u.v64); + + u.v64 = ioread64(mmio + GEN3_IMBAR2XLMT_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "IMBAR2XLMT -\t\t\t%#018llx\n", u.v64); + + if (ntb_topo_is_b2b(ndev->ntb.topo)) { + off += scnprintf(buf + off, buf_size - off, + "\nNTB Outgoing B2B XLAT:\n"); + + u.v64 = ioread64(mmio + GEN3_EMBAR1XBASE_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "EMBAR1XBASE -\t\t%#018llx\n", u.v64); + + u.v64 = ioread64(mmio + GEN3_EMBAR2XBASE_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "EMBAR2XBASE -\t\t%#018llx\n", u.v64); + + u.v64 = ioread64(mmio + GEN3_EMBAR1XLMT_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "EMBAR1XLMT -\t\t%#018llx\n", u.v64); + + u.v64 = ioread64(mmio + GEN3_EMBAR2XLMT_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "EMBAR2XLMT -\t\t%#018llx\n", u.v64); + + off += scnprintf(buf + off, buf_size - off, + "\nNTB Secondary BAR:\n"); + + u.v64 = ioread64(mmio + GEN3_EMBAR0_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "EMBAR0 -\t\t%#018llx\n", u.v64); + + u.v64 = ioread64(mmio + GEN3_EMBAR1_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "EMBAR1 -\t\t%#018llx\n", u.v64); + + u.v64 = ioread64(mmio + GEN3_EMBAR2_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "EMBAR2 -\t\t%#018llx\n", u.v64); + } + + off += scnprintf(buf + off, buf_size - off, + "\nNTB Statistics:\n"); + + u.v16 = ioread16(mmio + GEN3_USMEMMISS_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "Upstream Memory Miss -\t%u\n", u.v16); + + off += scnprintf(buf + off, buf_size - off, + "\nNTB Hardware Errors:\n"); + + if (!pci_read_config_word(ndev->ntb.pdev, + GEN3_DEVSTS_OFFSET, &u.v16)) + off += scnprintf(buf + off, buf_size - off, + "DEVSTS -\t\t%#06x\n", u.v16); + + if (!pci_read_config_word(ndev->ntb.pdev, + GEN3_LINK_STATUS_OFFSET, &u.v16)) + off += scnprintf(buf + off, buf_size - off, + "LNKSTS -\t\t%#06x\n", u.v16); + + if (!pci_read_config_dword(ndev->ntb.pdev, + GEN3_UNCERRSTS_OFFSET, &u.v32)) + off += scnprintf(buf + off, buf_size - off, + "UNCERRSTS -\t\t%#06x\n", u.v32); + + if (!pci_read_config_dword(ndev->ntb.pdev, + GEN3_CORERRSTS_OFFSET, &u.v32)) + off += scnprintf(buf + off, buf_size - off, + "CORERRSTS -\t\t%#06x\n", u.v32); + + ret = simple_read_from_buffer(ubuf, count, offp, buf, off); + kfree(buf); + return ret; +} + +static int intel_ntb3_link_enable(struct ntb_dev *ntb, + enum ntb_speed max_speed, + enum ntb_width max_width) +{ + struct intel_ntb_dev *ndev; + u32 ntb_ctl; + + ndev = container_of(ntb, struct intel_ntb_dev, ntb); + + dev_dbg(&ntb->pdev->dev, + "Enabling link with max_speed %d max_width %d\n", + max_speed, max_width); + + if (max_speed != NTB_SPEED_AUTO) + dev_dbg(&ntb->pdev->dev, "ignoring max_speed %d\n", max_speed); + if (max_width != NTB_WIDTH_AUTO) + dev_dbg(&ntb->pdev->dev, "ignoring max_width %d\n", max_width); + + ntb_ctl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl); + ntb_ctl &= ~(NTB_CTL_DISABLE | NTB_CTL_CFG_LOCK); + ntb_ctl |= NTB_CTL_P2S_BAR2_SNOOP | NTB_CTL_S2P_BAR2_SNOOP; + ntb_ctl |= NTB_CTL_P2S_BAR4_SNOOP | NTB_CTL_S2P_BAR4_SNOOP; + iowrite32(ntb_ctl, ndev->self_mmio + ndev->reg->ntb_ctl); + + return 0; +} +static int intel_ntb3_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx, + dma_addr_t addr, resource_size_t size) +{ + struct intel_ntb_dev *ndev = ntb_ndev(ntb); + unsigned long xlat_reg, limit_reg; + resource_size_t bar_size, mw_size; + void __iomem *mmio; + u64 base, limit, reg_val; + int bar; + + if (pidx != NTB_DEF_PEER_IDX) + return -EINVAL; + + if (idx >= ndev->b2b_idx && !ndev->b2b_off) + idx += 1; + + bar = ndev_mw_to_bar(ndev, idx); + if (bar < 0) + return bar; + + bar_size = pci_resource_len(ndev->ntb.pdev, bar); + + if (idx == ndev->b2b_idx) + mw_size = bar_size - ndev->b2b_off; + else + mw_size = bar_size; + + /* hardware requires that addr is aligned to bar size */ + if (addr & (bar_size - 1)) + return -EINVAL; + + /* make sure the range fits in the usable mw size */ + if (size > mw_size) + return -EINVAL; + + mmio = ndev->self_mmio; + xlat_reg = ndev->xlat_reg->bar2_xlat + (idx * 0x10); + limit_reg = ndev->xlat_reg->bar2_limit + (idx * 0x10); + base = pci_resource_start(ndev->ntb.pdev, bar); + + /* Set the limit if supported, if size is not mw_size */ + if (limit_reg && size != mw_size) + limit = base + size; + else + limit = base + mw_size; + + /* set and verify setting the translation address */ + iowrite64(addr, mmio + xlat_reg); + reg_val = ioread64(mmio + xlat_reg); + if (reg_val != addr) { + iowrite64(0, mmio + xlat_reg); + return -EIO; + } + + dev_dbg(&ntb->pdev->dev, "BAR %d IMBARXBASE: %#Lx\n", bar, reg_val); + + /* set and verify setting the limit */ + iowrite64(limit, mmio + limit_reg); + reg_val = ioread64(mmio + limit_reg); + if (reg_val != limit) { + iowrite64(base, mmio + limit_reg); + iowrite64(0, mmio + xlat_reg); + return -EIO; + } + + dev_dbg(&ntb->pdev->dev, "BAR %d IMBARXLMT: %#Lx\n", bar, reg_val); + + /* setup the EP */ + limit_reg = ndev->xlat_reg->bar2_limit + (idx * 0x10) + 0x4000; + base = ioread64(mmio + GEN3_EMBAR1_OFFSET + (8 * idx)); + base &= ~0xf; + + if (limit_reg && size != mw_size) + limit = base + size; + else + limit = base + mw_size; + + /* set and verify setting the limit */ + iowrite64(limit, mmio + limit_reg); + reg_val = ioread64(mmio + limit_reg); + if (reg_val != limit) { + iowrite64(base, mmio + limit_reg); + iowrite64(0, mmio + xlat_reg); + return -EIO; + } + + dev_dbg(&ntb->pdev->dev, "BAR %d EMBARXLMT: %#Lx\n", bar, reg_val); + + return 0; +} + +static int intel_ntb3_peer_db_set(struct ntb_dev *ntb, u64 db_bits) +{ + struct intel_ntb_dev *ndev = ntb_ndev(ntb); + int bit; + + if (db_bits & ~ndev->db_valid_mask) + return -EINVAL; + + while (db_bits) { + bit = __ffs(db_bits); + iowrite32(1, ndev->peer_mmio + + ndev->peer_reg->db_bell + (bit * 4)); + db_bits &= db_bits - 1; + } + + return 0; +} + +static u64 intel_ntb3_db_read(struct ntb_dev *ntb) +{ + struct intel_ntb_dev *ndev = ntb_ndev(ntb); + + return ndev_db_read(ndev, + ndev->self_mmio + + ndev->self_reg->db_clear); +} + +static int intel_ntb3_db_clear(struct ntb_dev *ntb, u64 db_bits) +{ + struct intel_ntb_dev *ndev = ntb_ndev(ntb); + + return ndev_db_write(ndev, db_bits, + ndev->self_mmio + + ndev->self_reg->db_clear); +} + +const struct ntb_dev_ops intel_ntb3_ops = { + .mw_count = intel_ntb_mw_count, + .mw_get_align = intel_ntb_mw_get_align, + .mw_set_trans = intel_ntb3_mw_set_trans, + .peer_mw_count = intel_ntb_peer_mw_count, + .peer_mw_get_addr = intel_ntb_peer_mw_get_addr, + .link_is_up = intel_ntb_link_is_up, + .link_enable = intel_ntb3_link_enable, + .link_disable = intel_ntb_link_disable, + .db_valid_mask = intel_ntb_db_valid_mask, + .db_vector_count = intel_ntb_db_vector_count, + .db_vector_mask = intel_ntb_db_vector_mask, + .db_read = intel_ntb3_db_read, + .db_clear = intel_ntb3_db_clear, + .db_set_mask = intel_ntb_db_set_mask, + .db_clear_mask = intel_ntb_db_clear_mask, + .peer_db_addr = intel_ntb_peer_db_addr, + .peer_db_set = intel_ntb3_peer_db_set, + .spad_is_unsafe = intel_ntb_spad_is_unsafe, + .spad_count = intel_ntb_spad_count, + .spad_read = intel_ntb_spad_read, + .spad_write = intel_ntb_spad_write, + .peer_spad_addr = intel_ntb_peer_spad_addr, + .peer_spad_read = intel_ntb_peer_spad_read, + .peer_spad_write = intel_ntb_peer_spad_write, +}; + diff --git a/drivers/ntb/hw/intel/ntb_hw_gen3.h b/drivers/ntb/hw/intel/ntb_hw_gen3.h new file mode 100644 index 000000000000..75fb86ca27bb --- /dev/null +++ b/drivers/ntb/hw/intel/ntb_hw_gen3.h @@ -0,0 +1,110 @@ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2012-2017 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * BSD LICENSE + * + * Copyright(c) 2012-2017 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copy + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _NTB_INTEL_GEN3_H_ +#define _NTB_INTEL_GEN3_H_ + +#include "ntb_hw_intel.h" + +/* Intel Skylake Xeon hardware */ +#define GEN3_IMBAR1SZ_OFFSET 0x00d0 +#define GEN3_IMBAR2SZ_OFFSET 0x00d1 +#define GEN3_EMBAR1SZ_OFFSET 0x00d2 +#define GEN3_EMBAR2SZ_OFFSET 0x00d3 +#define GEN3_DEVCTRL_OFFSET 0x0098 +#define GEN3_DEVSTS_OFFSET 0x009a +#define GEN3_UNCERRSTS_OFFSET 0x014c +#define GEN3_CORERRSTS_OFFSET 0x0158 +#define GEN3_LINK_STATUS_OFFSET 0x01a2 + +#define GEN3_NTBCNTL_OFFSET 0x0000 +#define GEN3_IMBAR1XBASE_OFFSET 0x0010 /* SBAR2XLAT */ +#define GEN3_IMBAR1XLMT_OFFSET 0x0018 /* SBAR2LMT */ +#define GEN3_IMBAR2XBASE_OFFSET 0x0020 /* SBAR4XLAT */ +#define GEN3_IMBAR2XLMT_OFFSET 0x0028 /* SBAR4LMT */ +#define GEN3_IM_INT_STATUS_OFFSET 0x0040 +#define GEN3_IM_INT_DISABLE_OFFSET 0x0048 +#define GEN3_IM_SPAD_OFFSET 0x0080 /* SPAD */ +#define GEN3_USMEMMISS_OFFSET 0x0070 +#define GEN3_INTVEC_OFFSET 0x00d0 +#define GEN3_IM_DOORBELL_OFFSET 0x0100 /* SDOORBELL0 */ +#define GEN3_B2B_SPAD_OFFSET 0x0180 /* B2B SPAD */ +#define GEN3_EMBAR0XBASE_OFFSET 0x4008 /* B2B_XLAT */ +#define GEN3_EMBAR1XBASE_OFFSET 0x4010 /* PBAR2XLAT */ +#define GEN3_EMBAR1XLMT_OFFSET 0x4018 /* PBAR2LMT */ +#define GEN3_EMBAR2XBASE_OFFSET 0x4020 /* PBAR4XLAT */ +#define GEN3_EMBAR2XLMT_OFFSET 0x4028 /* PBAR4LMT */ +#define GEN3_EM_INT_STATUS_OFFSET 0x4040 +#define GEN3_EM_INT_DISABLE_OFFSET 0x4048 +#define GEN3_EM_SPAD_OFFSET 0x4080 /* remote SPAD */ +#define GEN3_EM_DOORBELL_OFFSET 0x4100 /* PDOORBELL0 */ +#define GEN3_SPCICMD_OFFSET 0x4504 /* SPCICMD */ +#define GEN3_EMBAR0_OFFSET 0x4510 /* SBAR0BASE */ +#define GEN3_EMBAR1_OFFSET 0x4518 /* SBAR23BASE */ +#define GEN3_EMBAR2_OFFSET 0x4520 /* SBAR45BASE */ + +#define GEN3_DB_COUNT 32 +#define GEN3_DB_LINK 32 +#define GEN3_DB_LINK_BIT BIT_ULL(GEN3_DB_LINK) +#define GEN3_DB_MSIX_VECTOR_COUNT 33 +#define GEN3_DB_MSIX_VECTOR_SHIFT 1 +#define GEN3_DB_TOTAL_SHIFT 33 +#define GEN3_SPAD_COUNT 16 + +static inline u64 gen3_db_ioread(void __iomem *mmio) +{ + return ioread64(mmio); +} + +static inline void gen3_db_iowrite(u64 bits, void __iomem *mmio) +{ + iowrite64(bits, mmio); +} + +ssize_t ndev_ntb3_debugfs_read(struct file *filp, char __user *ubuf, + size_t count, loff_t *offp); +int gen3_init_dev(struct intel_ntb_dev *ndev); + +extern const struct ntb_dev_ops intel_ntb3_ops; + +#endif diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.h b/drivers/ntb/hw/intel/ntb_hw_intel.h index 4415aa7ea775..c49ff8970ce3 100644 --- a/drivers/ntb/hw/intel/ntb_hw_intel.h +++ b/drivers/ntb/hw/intel/ntb_hw_intel.h @@ -54,6 +54,7 @@ #include <linux/ntb.h> #include <linux/pci.h> +/* PCI device IDs */ #define PCI_DEVICE_ID_INTEL_NTB_B2B_JSF 0x3725 #define PCI_DEVICE_ID_INTEL_NTB_PS_JSF 0x3726 #define PCI_DEVICE_ID_INTEL_NTB_SS_JSF 0x3727 @@ -71,132 +72,7 @@ #define PCI_DEVICE_ID_INTEL_NTB_SS_BDX 0x6F0F #define PCI_DEVICE_ID_INTEL_NTB_B2B_SKX 0x201C -/* Intel Xeon hardware */ - -#define XEON_PBAR23LMT_OFFSET 0x0000 -#define XEON_PBAR45LMT_OFFSET 0x0008 -#define XEON_PBAR4LMT_OFFSET 0x0008 -#define XEON_PBAR5LMT_OFFSET 0x000c -#define XEON_PBAR23XLAT_OFFSET 0x0010 -#define XEON_PBAR45XLAT_OFFSET 0x0018 -#define XEON_PBAR4XLAT_OFFSET 0x0018 -#define XEON_PBAR5XLAT_OFFSET 0x001c -#define XEON_SBAR23LMT_OFFSET 0x0020 -#define XEON_SBAR45LMT_OFFSET 0x0028 -#define XEON_SBAR4LMT_OFFSET 0x0028 -#define XEON_SBAR5LMT_OFFSET 0x002c -#define XEON_SBAR23XLAT_OFFSET 0x0030 -#define XEON_SBAR45XLAT_OFFSET 0x0038 -#define XEON_SBAR4XLAT_OFFSET 0x0038 -#define XEON_SBAR5XLAT_OFFSET 0x003c -#define XEON_SBAR0BASE_OFFSET 0x0040 -#define XEON_SBAR23BASE_OFFSET 0x0048 -#define XEON_SBAR45BASE_OFFSET 0x0050 -#define XEON_SBAR4BASE_OFFSET 0x0050 -#define XEON_SBAR5BASE_OFFSET 0x0054 -#define XEON_SBDF_OFFSET 0x005c -#define XEON_NTBCNTL_OFFSET 0x0058 -#define XEON_PDOORBELL_OFFSET 0x0060 -#define XEON_PDBMSK_OFFSET 0x0062 -#define XEON_SDOORBELL_OFFSET 0x0064 -#define XEON_SDBMSK_OFFSET 0x0066 -#define XEON_USMEMMISS_OFFSET 0x0070 -#define XEON_SPAD_OFFSET 0x0080 -#define XEON_PBAR23SZ_OFFSET 0x00d0 -#define XEON_PBAR45SZ_OFFSET 0x00d1 -#define XEON_PBAR4SZ_OFFSET 0x00d1 -#define XEON_SBAR23SZ_OFFSET 0x00d2 -#define XEON_SBAR45SZ_OFFSET 0x00d3 -#define XEON_SBAR4SZ_OFFSET 0x00d3 -#define XEON_PPD_OFFSET 0x00d4 -#define XEON_PBAR5SZ_OFFSET 0x00d5 -#define XEON_SBAR5SZ_OFFSET 0x00d6 -#define XEON_WCCNTRL_OFFSET 0x00e0 -#define XEON_UNCERRSTS_OFFSET 0x014c -#define XEON_CORERRSTS_OFFSET 0x0158 -#define XEON_LINK_STATUS_OFFSET 0x01a2 -#define XEON_SPCICMD_OFFSET 0x0504 -#define XEON_DEVCTRL_OFFSET 0x0598 -#define XEON_DEVSTS_OFFSET 0x059a -#define XEON_SLINK_STATUS_OFFSET 0x05a2 -#define XEON_B2B_SPAD_OFFSET 0x0100 -#define XEON_B2B_DOORBELL_OFFSET 0x0140 -#define XEON_B2B_XLAT_OFFSETL 0x0144 -#define XEON_B2B_XLAT_OFFSETU 0x0148 -#define XEON_PPD_CONN_MASK 0x03 -#define XEON_PPD_CONN_TRANSPARENT 0x00 -#define XEON_PPD_CONN_B2B 0x01 -#define XEON_PPD_CONN_RP 0x02 -#define XEON_PPD_DEV_MASK 0x10 -#define XEON_PPD_DEV_USD 0x00 -#define XEON_PPD_DEV_DSD 0x10 -#define XEON_PPD_SPLIT_BAR_MASK 0x40 - -#define XEON_PPD_TOPO_MASK (XEON_PPD_CONN_MASK | XEON_PPD_DEV_MASK) -#define XEON_PPD_TOPO_PRI_USD (XEON_PPD_CONN_RP | XEON_PPD_DEV_USD) -#define XEON_PPD_TOPO_PRI_DSD (XEON_PPD_CONN_RP | XEON_PPD_DEV_DSD) -#define XEON_PPD_TOPO_SEC_USD (XEON_PPD_CONN_TRANSPARENT | XEON_PPD_DEV_USD) -#define XEON_PPD_TOPO_SEC_DSD (XEON_PPD_CONN_TRANSPARENT | XEON_PPD_DEV_DSD) -#define XEON_PPD_TOPO_B2B_USD (XEON_PPD_CONN_B2B | XEON_PPD_DEV_USD) -#define XEON_PPD_TOPO_B2B_DSD (XEON_PPD_CONN_B2B | XEON_PPD_DEV_DSD) - -#define XEON_MW_COUNT 2 -#define HSX_SPLIT_BAR_MW_COUNT 3 -#define XEON_DB_COUNT 15 -#define XEON_DB_LINK 15 -#define XEON_DB_LINK_BIT BIT_ULL(XEON_DB_LINK) -#define XEON_DB_MSIX_VECTOR_COUNT 4 -#define XEON_DB_MSIX_VECTOR_SHIFT 5 -#define XEON_DB_TOTAL_SHIFT 16 -#define XEON_SPAD_COUNT 16 - -/* Intel Skylake Xeon hardware */ -#define SKX_IMBAR1SZ_OFFSET 0x00d0 -#define SKX_IMBAR2SZ_OFFSET 0x00d1 -#define SKX_EMBAR1SZ_OFFSET 0x00d2 -#define SKX_EMBAR2SZ_OFFSET 0x00d3 -#define SKX_DEVCTRL_OFFSET 0x0098 -#define SKX_DEVSTS_OFFSET 0x009a -#define SKX_UNCERRSTS_OFFSET 0x014c -#define SKX_CORERRSTS_OFFSET 0x0158 -#define SKX_LINK_STATUS_OFFSET 0x01a2 - -#define SKX_NTBCNTL_OFFSET 0x0000 -#define SKX_IMBAR1XBASE_OFFSET 0x0010 /* SBAR2XLAT */ -#define SKX_IMBAR1XLMT_OFFSET 0x0018 /* SBAR2LMT */ -#define SKX_IMBAR2XBASE_OFFSET 0x0020 /* SBAR4XLAT */ -#define SKX_IMBAR2XLMT_OFFSET 0x0028 /* SBAR4LMT */ -#define SKX_IM_INT_STATUS_OFFSET 0x0040 -#define SKX_IM_INT_DISABLE_OFFSET 0x0048 -#define SKX_IM_SPAD_OFFSET 0x0080 /* SPAD */ -#define SKX_USMEMMISS_OFFSET 0x0070 -#define SKX_INTVEC_OFFSET 0x00d0 -#define SKX_IM_DOORBELL_OFFSET 0x0100 /* SDOORBELL0 */ -#define SKX_B2B_SPAD_OFFSET 0x0180 /* B2B SPAD */ -#define SKX_EMBAR0XBASE_OFFSET 0x4008 /* B2B_XLAT */ -#define SKX_EMBAR1XBASE_OFFSET 0x4010 /* PBAR2XLAT */ -#define SKX_EMBAR1XLMT_OFFSET 0x4018 /* PBAR2LMT */ -#define SKX_EMBAR2XBASE_OFFSET 0x4020 /* PBAR4XLAT */ -#define SKX_EMBAR2XLMT_OFFSET 0x4028 /* PBAR4LMT */ -#define SKX_EM_INT_STATUS_OFFSET 0x4040 -#define SKX_EM_INT_DISABLE_OFFSET 0x4048 -#define SKX_EM_SPAD_OFFSET 0x4080 /* remote SPAD */ -#define SKX_EM_DOORBELL_OFFSET 0x4100 /* PDOORBELL0 */ -#define SKX_SPCICMD_OFFSET 0x4504 /* SPCICMD */ -#define SKX_EMBAR0_OFFSET 0x4510 /* SBAR0BASE */ -#define SKX_EMBAR1_OFFSET 0x4518 /* SBAR23BASE */ -#define SKX_EMBAR2_OFFSET 0x4520 /* SBAR45BASE */ - -#define SKX_DB_COUNT 32 -#define SKX_DB_LINK 32 -#define SKX_DB_LINK_BIT BIT_ULL(SKX_DB_LINK) -#define SKX_DB_MSIX_VECTOR_COUNT 33 -#define SKX_DB_MSIX_VECTOR_SHIFT 1 -#define SKX_DB_TOTAL_SHIFT 33 -#define SKX_SPAD_COUNT 16 - /* Ntb control and link status */ - #define NTB_CTL_CFG_LOCK BIT(0) #define NTB_CTL_DISABLE BIT(1) #define NTB_CTL_S2P_BAR2_SNOOP BIT(2) @@ -213,23 +89,6 @@ #define NTB_LNK_STA_SPEED(x) ((x) & NTB_LNK_STA_SPEED_MASK) #define NTB_LNK_STA_WIDTH(x) (((x) & NTB_LNK_STA_WIDTH_MASK) >> 4) -/* Use the following addresses for translation between b2b ntb devices in case - * the hardware default values are not reliable. */ -#define XEON_B2B_BAR0_ADDR 0x1000000000000000ull -#define XEON_B2B_BAR2_ADDR64 0x2000000000000000ull -#define XEON_B2B_BAR4_ADDR64 0x4000000000000000ull -#define XEON_B2B_BAR4_ADDR32 0x20000000u -#define XEON_B2B_BAR5_ADDR32 0x40000000u - -/* The peer ntb secondary config space is 32KB fixed size */ -#define XEON_B2B_MIN_SIZE 0x8000 - -/* flags to indicate hardware errata */ -#define NTB_HWERR_SDOORBELL_LOCKUP BIT_ULL(0) -#define NTB_HWERR_SB01BASE_LOCKUP BIT_ULL(1) -#define NTB_HWERR_B2BDOORBELL_BIT14 BIT_ULL(2) -#define NTB_HWERR_MSIX_VECTOR32_BAD BIT_ULL(3) - /* flags to indicate unsafe api */ #define NTB_UNSAFE_DB BIT_ULL(0) #define NTB_UNSAFE_SPAD BIT_ULL(1) @@ -328,4 +187,64 @@ struct intel_ntb_dev { #define hb_ndev(__work) container_of(__work, struct intel_ntb_dev, \ hb_timer.work) +static inline int pdev_is_gen1(struct pci_dev *pdev) +{ + switch (pdev->device) { + case PCI_DEVICE_ID_INTEL_NTB_SS_JSF: + case PCI_DEVICE_ID_INTEL_NTB_SS_SNB: + case PCI_DEVICE_ID_INTEL_NTB_SS_IVT: + case PCI_DEVICE_ID_INTEL_NTB_SS_HSX: + case PCI_DEVICE_ID_INTEL_NTB_SS_BDX: + case PCI_DEVICE_ID_INTEL_NTB_PS_JSF: + case PCI_DEVICE_ID_INTEL_NTB_PS_SNB: + case PCI_DEVICE_ID_INTEL_NTB_PS_IVT: + case PCI_DEVICE_ID_INTEL_NTB_PS_HSX: + case PCI_DEVICE_ID_INTEL_NTB_PS_BDX: + case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF: + case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB: + case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT: + case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX: + case PCI_DEVICE_ID_INTEL_NTB_B2B_BDX: + return 1; + } + return 0; +} + +static inline int pdev_is_gen3(struct pci_dev *pdev) +{ + if (pdev->device == PCI_DEVICE_ID_INTEL_NTB_B2B_SKX) + return 1; + + return 0; +} + +#ifndef ioread64 +#ifdef readq +#define ioread64 readq +#else +#define ioread64 _ioread64 +static inline u64 _ioread64(void __iomem *mmio) +{ + u64 low, high; + + low = ioread32(mmio); + high = ioread32(mmio + sizeof(u32)); + return low | (high << 32); +} +#endif +#endif + +#ifndef iowrite64 +#ifdef writeq +#define iowrite64 writeq +#else +#define iowrite64 _iowrite64 +static inline void _iowrite64(u64 val, void __iomem *mmio) +{ + iowrite32(val, mmio); + iowrite32(val >> 32, mmio + sizeof(u32)); +} +#endif +#endif + #endif diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index 9878c48826e3..939895966476 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -637,7 +637,7 @@ static int ntb_transport_setup_qp_mw(struct ntb_transport_ctx *nt, */ node = dev_to_node(&ndev->dev); for (i = qp->rx_alloc_entry; i < qp->rx_max_entry; i++) { - entry = kzalloc_node(sizeof(*entry), GFP_ATOMIC, node); + entry = kzalloc_node(sizeof(*entry), GFP_KERNEL, node); if (!entry) return -ENOMEM; @@ -1102,7 +1102,7 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev) max_mw_count_for_spads = (spad_count - MW0_SZ_HIGH) / 2; nt->mw_count = min(mw_count, max_mw_count_for_spads); - nt->mw_vec = kzalloc_node(mw_count * sizeof(*nt->mw_vec), + nt->mw_vec = kcalloc_node(mw_count, sizeof(*nt->mw_vec), GFP_KERNEL, node); if (!nt->mw_vec) { rc = -ENOMEM; @@ -1143,7 +1143,7 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev) nt->qp_bitmap = qp_bitmap; nt->qp_bitmap_free = qp_bitmap; - nt->qp_vec = kzalloc_node(qp_count * sizeof(*nt->qp_vec), + nt->qp_vec = kcalloc_node(qp_count, sizeof(*nt->qp_vec), GFP_KERNEL, node); if (!nt->qp_vec) { rc = -ENOMEM; @@ -1828,7 +1828,7 @@ ntb_transport_create_queue(void *data, struct device *client_dev, qp->rx_dma_chan ? "DMA" : "CPU"); for (i = 0; i < NTB_QP_DEF_NUM_ENTRIES; i++) { - entry = kzalloc_node(sizeof(*entry), GFP_ATOMIC, node); + entry = kzalloc_node(sizeof(*entry), GFP_KERNEL, node); if (!entry) goto err1; @@ -1839,7 +1839,7 @@ ntb_transport_create_queue(void *data, struct device *client_dev, qp->rx_alloc_entry = NTB_QP_DEF_NUM_ENTRIES; for (i = 0; i < qp->tx_max_entry; i++) { - entry = kzalloc_node(sizeof(*entry), GFP_ATOMIC, node); + entry = kzalloc_node(sizeof(*entry), GFP_KERNEL, node); if (!entry) goto err2; diff --git a/drivers/nvmem/rockchip-efuse.c b/drivers/nvmem/rockchip-efuse.c index b3b0b648be62..146de9489339 100644 --- a/drivers/nvmem/rockchip-efuse.c +++ b/drivers/nvmem/rockchip-efuse.c @@ -122,7 +122,8 @@ static int rockchip_rk3328_efuse_read(void *context, unsigned int offset, addr_offset = offset % RK3399_NBYTES; addr_len = addr_end - addr_start; - buf = kzalloc(sizeof(*buf) * addr_len * RK3399_NBYTES, GFP_KERNEL); + buf = kzalloc(array3_size(addr_len, RK3399_NBYTES, sizeof(*buf)), + GFP_KERNEL); if (!buf) { ret = -ENOMEM; goto nomem; @@ -174,7 +175,8 @@ static int rockchip_rk3399_efuse_read(void *context, unsigned int offset, addr_offset = offset % RK3399_NBYTES; addr_len = addr_end - addr_start; - buf = kzalloc(sizeof(*buf) * addr_len * RK3399_NBYTES, GFP_KERNEL); + buf = kzalloc(array3_size(addr_len, RK3399_NBYTES, sizeof(*buf)), + GFP_KERNEL); if (!buf) { clk_disable_unprepare(efuse->clk); return -ENOMEM; diff --git a/drivers/nvmem/sunxi_sid.c b/drivers/nvmem/sunxi_sid.c index 26bb637afe92..d020f89248fd 100644 --- a/drivers/nvmem/sunxi_sid.c +++ b/drivers/nvmem/sunxi_sid.c @@ -185,7 +185,7 @@ static int sunxi_sid_probe(struct platform_device *pdev) if (IS_ERR(nvmem)) return PTR_ERR(nvmem); - randomness = kzalloc(sizeof(u8) * (size), GFP_KERNEL); + randomness = kzalloc(size, GFP_KERNEL); if (!randomness) { ret = -EINVAL; goto err_unreg_nvmem; diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 0b49a62b38a3..6925d993e1f0 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -129,7 +129,7 @@ struct platform_device *of_device_alloc(struct device_node *np, /* Populate the resource table */ if (num_irq || num_reg) { - res = kzalloc(sizeof(*res) * (num_irq + num_reg), GFP_KERNEL); + res = kcalloc(num_irq + num_reg, sizeof(*res), GFP_KERNEL); if (!res) { platform_device_put(dev); return NULL; @@ -505,6 +505,7 @@ EXPORT_SYMBOL_GPL(of_platform_default_populate); #ifndef CONFIG_PPC static const struct of_device_id reserved_mem_matches[] = { { .compatible = "qcom,rmtfs-mem" }, + { .compatible = "qcom,cmd-db" }, { .compatible = "ramoops" }, {} }; diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index ecee50d10d14..722537e14848 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -156,7 +156,7 @@ static void __init of_unittest_dynamic(void) } /* Array of 4 properties for the purpose of testing */ - prop = kzalloc(sizeof(*prop) * 4, GFP_KERNEL); + prop = kcalloc(4, sizeof(*prop), GFP_KERNEL); if (!prop) { unittest(0, "kzalloc() failed\n"); return; diff --git a/drivers/opp/ti-opp-supply.c b/drivers/opp/ti-opp-supply.c index 370eff3acd8a..9e5a9a3112c9 100644 --- a/drivers/opp/ti-opp-supply.c +++ b/drivers/opp/ti-opp-supply.c @@ -122,8 +122,8 @@ static int _store_optimized_voltages(struct device *dev, goto out; } - table = kzalloc(sizeof(*data->vdd_table) * - data->num_vdd_table, GFP_KERNEL); + table = kcalloc(data->num_vdd_table, sizeof(*data->vdd_table), + GFP_KERNEL); if (!table) { ret = -ENOMEM; goto out; diff --git a/drivers/oprofile/event_buffer.c b/drivers/oprofile/event_buffer.c index 32888f2bd1a9..12ea4a4ad607 100644 --- a/drivers/oprofile/event_buffer.c +++ b/drivers/oprofile/event_buffer.c @@ -91,7 +91,7 @@ int alloc_event_buffer(void) return -EINVAL; buffer_pos = 0; - event_buffer = vmalloc(sizeof(unsigned long) * buffer_size); + event_buffer = vmalloc(array_size(buffer_size, sizeof(unsigned long))); if (!event_buffer) return -ENOMEM; diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index b2f07635e94d..56ff8f6d31fc 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -145,8 +145,6 @@ config PCI_HYPERV PCI devices from a PCI backend to support PCI driver domains. source "drivers/pci/hotplug/Kconfig" -source "drivers/pci/cadence/Kconfig" -source "drivers/pci/dwc/Kconfig" -source "drivers/pci/host/Kconfig" +source "drivers/pci/controller/Kconfig" source "drivers/pci/endpoint/Kconfig" source "drivers/pci/switch/Kconfig" diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 84c9eef6b1c3..535201984b8b 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -28,14 +28,10 @@ obj-$(CONFIG_PCI_PF_STUB) += pci-pf-stub.o obj-$(CONFIG_PCI_ECAM) += ecam.o obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += xen-pcifront.o -obj-y += host/ +obj-y += controller/ obj-y += switch/ # Endpoint library must be initialized before its users obj-$(CONFIG_PCI_ENDPOINT) += endpoint/ -obj-$(CONFIG_PCIE_CADENCE) += cadence/ -# pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW -obj-y += dwc/ - ccflags-$(CONFIG_PCI_DEBUG) := -DDEBUG diff --git a/drivers/pci/cadence/Kconfig b/drivers/pci/cadence/Kconfig deleted file mode 100644 index e6824cb56c16..000000000000 --- a/drivers/pci/cadence/Kconfig +++ /dev/null @@ -1,27 +0,0 @@ -menu "Cadence PCIe controllers support" - -config PCIE_CADENCE - bool - -config PCIE_CADENCE_HOST - bool "Cadence PCIe host controller" - depends on OF - depends on PCI - select IRQ_DOMAIN - select PCIE_CADENCE - help - Say Y here if you want to support the Cadence PCIe controller in host - mode. This PCIe controller may be embedded into many different vendors - SoCs. - -config PCIE_CADENCE_EP - bool "Cadence PCIe endpoint controller" - depends on OF - depends on PCI_ENDPOINT - select PCIE_CADENCE - help - Say Y here if you want to support the Cadence PCIe controller in - endpoint mode. This PCIe controller may be embedded into many - different vendors SoCs. - -endmenu diff --git a/drivers/pci/cadence/Makefile b/drivers/pci/cadence/Makefile deleted file mode 100644 index 719392b97998..000000000000 --- a/drivers/pci/cadence/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_PCIE_CADENCE) += pcie-cadence.o -obj-$(CONFIG_PCIE_CADENCE_HOST) += pcie-cadence-host.o -obj-$(CONFIG_PCIE_CADENCE_EP) += pcie-cadence-ep.o diff --git a/drivers/pci/host/Kconfig b/drivers/pci/controller/Kconfig index a96e23bda664..18fa09b3ac8f 100644 --- a/drivers/pci/host/Kconfig +++ b/drivers/pci/controller/Kconfig @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 -menu "PCI host controller drivers" +menu "PCI controller drivers" depends on PCI config PCI_MVEBU @@ -20,6 +20,34 @@ config PCI_AARDVARK controller is part of the South Bridge of the Marvel Armada 3700 SoC. +menu "Cadence PCIe controllers support" + +config PCIE_CADENCE + bool + +config PCIE_CADENCE_HOST + bool "Cadence PCIe host controller" + depends on OF + depends on PCI + select IRQ_DOMAIN + select PCIE_CADENCE + help + Say Y here if you want to support the Cadence PCIe controller in host + mode. This PCIe controller may be embedded into many different vendors + SoCs. + +config PCIE_CADENCE_EP + bool "Cadence PCIe endpoint controller" + depends on OF + depends on PCI_ENDPOINT + select PCIE_CADENCE + help + Say Y here if you want to support the Cadence PCIe controller in + endpoint mode. This PCIe controller may be embedded into many + different vendors SoCs. + +endmenu + config PCIE_XILINX_NWL bool "NWL PCIe Core" depends on ARCH_ZYNQMP || COMPILE_TEST @@ -243,4 +271,5 @@ config VMD To compile this driver as a module, choose M here: the module will be called vmd. +source "drivers/pci/controller/dwc/Kconfig" endmenu diff --git a/drivers/pci/host/Makefile b/drivers/pci/controller/Makefile index 11d21b026d37..24322b92f200 100644 --- a/drivers/pci/host/Makefile +++ b/drivers/pci/controller/Makefile @@ -1,4 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_PCIE_CADENCE) += pcie-cadence.o +obj-$(CONFIG_PCIE_CADENCE_HOST) += pcie-cadence-host.o +obj-$(CONFIG_PCIE_CADENCE_EP) += pcie-cadence-ep.o obj-$(CONFIG_PCI_FTPCI100) += pci-ftpci100.o obj-$(CONFIG_PCI_HYPERV) += pci-hyperv.o obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o @@ -25,6 +28,9 @@ obj-$(CONFIG_PCIE_ROCKCHIP_HOST) += pcie-rockchip-host.o obj-$(CONFIG_PCIE_MEDIATEK) += pcie-mediatek.o obj-$(CONFIG_PCIE_TANGO_SMP8759) += pcie-tango.o obj-$(CONFIG_VMD) += vmd.o +# pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW +obj-y += dwc/ + # The following drivers are for devices that use the generic ACPI # pci_root.c driver but don't support standard ECAM config access. diff --git a/drivers/pci/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig index 16f52c626b4b..16f52c626b4b 100644 --- a/drivers/pci/dwc/Kconfig +++ b/drivers/pci/controller/dwc/Kconfig diff --git a/drivers/pci/dwc/Makefile b/drivers/pci/controller/dwc/Makefile index 5d2ce72c7a52..5d2ce72c7a52 100644 --- a/drivers/pci/dwc/Makefile +++ b/drivers/pci/controller/dwc/Makefile diff --git a/drivers/pci/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c index f688204e50c5..345aab56ce8b 100644 --- a/drivers/pci/dwc/pci-dra7xx.c +++ b/drivers/pci/controller/dwc/pci-dra7xx.c @@ -27,7 +27,7 @@ #include <linux/mfd/syscon.h> #include <linux/regmap.h> -#include "../pci.h" +#include "../../pci.h" #include "pcie-designware.h" /* PCIe controller wrapper DRA7XX configuration registers */ @@ -639,11 +639,11 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev) return phy_count; } - phy = devm_kzalloc(dev, sizeof(*phy) * phy_count, GFP_KERNEL); + phy = devm_kcalloc(dev, phy_count, sizeof(*phy), GFP_KERNEL); if (!phy) return -ENOMEM; - link = devm_kzalloc(dev, sizeof(*link) * phy_count, GFP_KERNEL); + link = devm_kcalloc(dev, phy_count, sizeof(*link), GFP_KERNEL); if (!link) return -ENOMEM; diff --git a/drivers/pci/dwc/pci-exynos.c b/drivers/pci/controller/dwc/pci-exynos.c index 4cc1e5df8c79..4cc1e5df8c79 100644 --- a/drivers/pci/dwc/pci-exynos.c +++ b/drivers/pci/controller/dwc/pci-exynos.c diff --git a/drivers/pci/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 80f604602783..80f604602783 100644 --- a/drivers/pci/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c diff --git a/drivers/pci/dwc/pci-keystone-dw.c b/drivers/pci/controller/dwc/pci-keystone-dw.c index 0682213328e9..0682213328e9 100644 --- a/drivers/pci/dwc/pci-keystone-dw.c +++ b/drivers/pci/controller/dwc/pci-keystone-dw.c diff --git a/drivers/pci/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 3722a5f31e5e..3722a5f31e5e 100644 --- a/drivers/pci/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c diff --git a/drivers/pci/dwc/pci-keystone.h b/drivers/pci/controller/dwc/pci-keystone.h index 8a13da391543..8a13da391543 100644 --- a/drivers/pci/dwc/pci-keystone.h +++ b/drivers/pci/controller/dwc/pci-keystone.h diff --git a/drivers/pci/dwc/pci-layerscape.c b/drivers/pci/controller/dwc/pci-layerscape.c index 3724d3ef7008..3724d3ef7008 100644 --- a/drivers/pci/dwc/pci-layerscape.c +++ b/drivers/pci/controller/dwc/pci-layerscape.c diff --git a/drivers/pci/dwc/pcie-armada8k.c b/drivers/pci/controller/dwc/pcie-armada8k.c index 072fd7ecc29f..072fd7ecc29f 100644 --- a/drivers/pci/dwc/pcie-armada8k.c +++ b/drivers/pci/controller/dwc/pcie-armada8k.c diff --git a/drivers/pci/dwc/pcie-artpec6.c b/drivers/pci/controller/dwc/pcie-artpec6.c index 321b56cfd5d0..321b56cfd5d0 100644 --- a/drivers/pci/dwc/pcie-artpec6.c +++ b/drivers/pci/controller/dwc/pcie-artpec6.c diff --git a/drivers/pci/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 1eec4415a77f..8650416f6f9e 100644 --- a/drivers/pci/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -366,19 +366,21 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) return -EINVAL; } - ep->ib_window_map = devm_kzalloc(dev, sizeof(long) * + ep->ib_window_map = devm_kcalloc(dev, BITS_TO_LONGS(ep->num_ib_windows), + sizeof(long), GFP_KERNEL); if (!ep->ib_window_map) return -ENOMEM; - ep->ob_window_map = devm_kzalloc(dev, sizeof(long) * + ep->ob_window_map = devm_kcalloc(dev, BITS_TO_LONGS(ep->num_ob_windows), + sizeof(long), GFP_KERNEL); if (!ep->ob_window_map) return -ENOMEM; - addr = devm_kzalloc(dev, sizeof(phys_addr_t) * ep->num_ob_windows, + addr = devm_kcalloc(dev, ep->num_ob_windows, sizeof(phys_addr_t), GFP_KERNEL); if (!addr) return -ENOMEM; diff --git a/drivers/pci/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index cba1432e395d..781aa03aeede 100644 --- a/drivers/pci/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -15,7 +15,7 @@ #include <linux/pci_regs.h> #include <linux/platform_device.h> -#include "../pci.h" +#include "../../pci.h" #include "pcie-designware.h" static struct pci_ops dw_pcie_ops; diff --git a/drivers/pci/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c index 5937fed4c938..5937fed4c938 100644 --- a/drivers/pci/dwc/pcie-designware-plat.c +++ b/drivers/pci/controller/dwc/pcie-designware-plat.c diff --git a/drivers/pci/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 778c4f76a884..778c4f76a884 100644 --- a/drivers/pci/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c diff --git a/drivers/pci/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index bee4e2535a61..bee4e2535a61 100644 --- a/drivers/pci/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h diff --git a/drivers/pci/dwc/pcie-hisi.c b/drivers/pci/controller/dwc/pcie-hisi.c index 2658aaebb993..6d9e1b2b8f7b 100644 --- a/drivers/pci/dwc/pcie-hisi.c +++ b/drivers/pci/controller/dwc/pcie-hisi.c @@ -19,7 +19,7 @@ #include <linux/pci-acpi.h> #include <linux/pci-ecam.h> #include <linux/regmap.h> -#include "../pci.h" +#include "../../pci.h" #if defined(CONFIG_PCI_HISI) || (defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)) diff --git a/drivers/pci/dwc/pcie-histb.c b/drivers/pci/controller/dwc/pcie-histb.c index 3611d6ce9a92..3611d6ce9a92 100644 --- a/drivers/pci/dwc/pcie-histb.c +++ b/drivers/pci/controller/dwc/pcie-histb.c diff --git a/drivers/pci/dwc/pcie-kirin.c b/drivers/pci/controller/dwc/pcie-kirin.c index d2970a009eb5..d2970a009eb5 100644 --- a/drivers/pci/dwc/pcie-kirin.c +++ b/drivers/pci/controller/dwc/pcie-kirin.c diff --git a/drivers/pci/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index a1d0198081a6..a1d0198081a6 100644 --- a/drivers/pci/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c diff --git a/drivers/pci/dwc/pcie-spear13xx.c b/drivers/pci/controller/dwc/pcie-spear13xx.c index ecb58f7b7566..ecb58f7b7566 100644 --- a/drivers/pci/dwc/pcie-spear13xx.c +++ b/drivers/pci/controller/dwc/pcie-spear13xx.c diff --git a/drivers/pci/host/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c index d3172d5d3d35..d3172d5d3d35 100644 --- a/drivers/pci/host/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c diff --git a/drivers/pci/host/pci-ftpci100.c b/drivers/pci/controller/pci-ftpci100.c index a1ebe9ed441f..a1ebe9ed441f 100644 --- a/drivers/pci/host/pci-ftpci100.c +++ b/drivers/pci/controller/pci-ftpci100.c diff --git a/drivers/pci/host/pci-host-common.c b/drivers/pci/controller/pci-host-common.c index d8f10451f273..d8f10451f273 100644 --- a/drivers/pci/host/pci-host-common.c +++ b/drivers/pci/controller/pci-host-common.c diff --git a/drivers/pci/host/pci-host-generic.c b/drivers/pci/controller/pci-host-generic.c index dea3ec7592a2..dea3ec7592a2 100644 --- a/drivers/pci/host/pci-host-generic.c +++ b/drivers/pci/controller/pci-host-generic.c diff --git a/drivers/pci/host/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c index 6cc5036ac83c..6cc5036ac83c 100644 --- a/drivers/pci/host/pci-hyperv.c +++ b/drivers/pci/controller/pci-hyperv.c diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/controller/pci-mvebu.c index 23e270839e6a..23e270839e6a 100644 --- a/drivers/pci/host/pci-mvebu.c +++ b/drivers/pci/controller/pci-mvebu.c diff --git a/drivers/pci/host/pci-rcar-gen2.c b/drivers/pci/controller/pci-rcar-gen2.c index 326171cb1a97..326171cb1a97 100644 --- a/drivers/pci/host/pci-rcar-gen2.c +++ b/drivers/pci/controller/pci-rcar-gen2.c diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/controller/pci-tegra.c index f4f53d092e00..f4f53d092e00 100644 --- a/drivers/pci/host/pci-tegra.c +++ b/drivers/pci/controller/pci-tegra.c diff --git a/drivers/pci/host/pci-thunder-ecam.c b/drivers/pci/controller/pci-thunder-ecam.c index 32d1d7b81ef4..32d1d7b81ef4 100644 --- a/drivers/pci/host/pci-thunder-ecam.c +++ b/drivers/pci/controller/pci-thunder-ecam.c diff --git a/drivers/pci/host/pci-thunder-pem.c b/drivers/pci/controller/pci-thunder-pem.c index f127ce8bd4ef..f127ce8bd4ef 100644 --- a/drivers/pci/host/pci-thunder-pem.c +++ b/drivers/pci/controller/pci-thunder-pem.c diff --git a/drivers/pci/host/pci-v3-semi.c b/drivers/pci/controller/pci-v3-semi.c index 68b8bfbdb867..68b8bfbdb867 100644 --- a/drivers/pci/host/pci-v3-semi.c +++ b/drivers/pci/controller/pci-v3-semi.c diff --git a/drivers/pci/host/pci-versatile.c b/drivers/pci/controller/pci-versatile.c index 994f32061b32..994f32061b32 100644 --- a/drivers/pci/host/pci-versatile.c +++ b/drivers/pci/controller/pci-versatile.c diff --git a/drivers/pci/host/pci-xgene-msi.c b/drivers/pci/controller/pci-xgene-msi.c index f4c02da84e59..f4c02da84e59 100644 --- a/drivers/pci/host/pci-xgene-msi.c +++ b/drivers/pci/controller/pci-xgene-msi.c diff --git a/drivers/pci/host/pci-xgene.c b/drivers/pci/controller/pci-xgene.c index d854d67e873c..d854d67e873c 100644 --- a/drivers/pci/host/pci-xgene.c +++ b/drivers/pci/controller/pci-xgene.c diff --git a/drivers/pci/host/pcie-altera-msi.c b/drivers/pci/controller/pcie-altera-msi.c index 025ef7d9a046..025ef7d9a046 100644 --- a/drivers/pci/host/pcie-altera-msi.c +++ b/drivers/pci/controller/pcie-altera-msi.c diff --git a/drivers/pci/host/pcie-altera.c b/drivers/pci/controller/pcie-altera.c index 7d05e51205b3..7d05e51205b3 100644 --- a/drivers/pci/host/pcie-altera.c +++ b/drivers/pci/controller/pcie-altera.c diff --git a/drivers/pci/cadence/pcie-cadence-ep.c b/drivers/pci/controller/pcie-cadence-ep.c index 3d8283e450a9..e3fe4124e3af 100644 --- a/drivers/pci/cadence/pcie-cadence-ep.c +++ b/drivers/pci/controller/pcie-cadence-ep.c @@ -467,7 +467,8 @@ static int cdns_pcie_ep_probe(struct platform_device *pdev) dev_err(dev, "missing \"cdns,max-outbound-regions\"\n"); return ret; } - ep->ob_addr = devm_kzalloc(dev, ep->max_regions * sizeof(*ep->ob_addr), + ep->ob_addr = devm_kcalloc(dev, + ep->max_regions, sizeof(*ep->ob_addr), GFP_KERNEL); if (!ep->ob_addr) return -ENOMEM; diff --git a/drivers/pci/cadence/pcie-cadence-host.c b/drivers/pci/controller/pcie-cadence-host.c index a4ebbd37b553..a4ebbd37b553 100644 --- a/drivers/pci/cadence/pcie-cadence-host.c +++ b/drivers/pci/controller/pcie-cadence-host.c diff --git a/drivers/pci/cadence/pcie-cadence.c b/drivers/pci/controller/pcie-cadence.c index 138d113eb45d..138d113eb45d 100644 --- a/drivers/pci/cadence/pcie-cadence.c +++ b/drivers/pci/controller/pcie-cadence.c diff --git a/drivers/pci/cadence/pcie-cadence.h b/drivers/pci/controller/pcie-cadence.h index 4bb27333b05c..4bb27333b05c 100644 --- a/drivers/pci/cadence/pcie-cadence.h +++ b/drivers/pci/controller/pcie-cadence.h diff --git a/drivers/pci/host/pcie-iproc-bcma.c b/drivers/pci/controller/pcie-iproc-bcma.c index aa55b064f64d..aa55b064f64d 100644 --- a/drivers/pci/host/pcie-iproc-bcma.c +++ b/drivers/pci/controller/pcie-iproc-bcma.c diff --git a/drivers/pci/host/pcie-iproc-msi.c b/drivers/pci/controller/pcie-iproc-msi.c index 9deb56989d72..9deb56989d72 100644 --- a/drivers/pci/host/pcie-iproc-msi.c +++ b/drivers/pci/controller/pcie-iproc-msi.c diff --git a/drivers/pci/host/pcie-iproc-platform.c b/drivers/pci/controller/pcie-iproc-platform.c index f30f5f3fb5c1..f30f5f3fb5c1 100644 --- a/drivers/pci/host/pcie-iproc-platform.c +++ b/drivers/pci/controller/pcie-iproc-platform.c diff --git a/drivers/pci/host/pcie-iproc.c b/drivers/pci/controller/pcie-iproc.c index 3c76c5fa4f32..3c76c5fa4f32 100644 --- a/drivers/pci/host/pcie-iproc.c +++ b/drivers/pci/controller/pcie-iproc.c diff --git a/drivers/pci/host/pcie-iproc.h b/drivers/pci/controller/pcie-iproc.h index 814b600b383a..814b600b383a 100644 --- a/drivers/pci/host/pcie-iproc.h +++ b/drivers/pci/controller/pcie-iproc.h diff --git a/drivers/pci/host/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c index 0baabe30858f..0baabe30858f 100644 --- a/drivers/pci/host/pcie-mediatek.c +++ b/drivers/pci/controller/pcie-mediatek.c diff --git a/drivers/pci/host/pcie-mobiveil.c b/drivers/pci/controller/pcie-mobiveil.c index 4d6c20e47bed..4d6c20e47bed 100644 --- a/drivers/pci/host/pcie-mobiveil.c +++ b/drivers/pci/controller/pcie-mobiveil.c diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/controller/pcie-rcar.c index 874d75c9ee4a..874d75c9ee4a 100644 --- a/drivers/pci/host/pcie-rcar.c +++ b/drivers/pci/controller/pcie-rcar.c diff --git a/drivers/pci/host/pcie-rockchip-ep.c b/drivers/pci/controller/pcie-rockchip-ep.c index fc267a49a932..6beba8ed7b84 100644 --- a/drivers/pci/host/pcie-rockchip-ep.c +++ b/drivers/pci/controller/pcie-rockchip-ep.c @@ -593,7 +593,7 @@ static int rockchip_pcie_ep_probe(struct platform_device *pdev) PCIE_CLIENT_CONFIG); max_regions = ep->max_regions; - ep->ob_addr = devm_kzalloc(dev, max_regions * sizeof(*ep->ob_addr), + ep->ob_addr = devm_kcalloc(dev, max_regions, sizeof(*ep->ob_addr), GFP_KERNEL); if (!ep->ob_addr) { diff --git a/drivers/pci/host/pcie-rockchip-host.c b/drivers/pci/controller/pcie-rockchip-host.c index 1372d270764f..1372d270764f 100644 --- a/drivers/pci/host/pcie-rockchip-host.c +++ b/drivers/pci/controller/pcie-rockchip-host.c diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/controller/pcie-rockchip.c index c53d1322a3d6..c53d1322a3d6 100644 --- a/drivers/pci/host/pcie-rockchip.c +++ b/drivers/pci/controller/pcie-rockchip.c diff --git a/drivers/pci/host/pcie-rockchip.h b/drivers/pci/controller/pcie-rockchip.h index 8e87a059ce73..8e87a059ce73 100644 --- a/drivers/pci/host/pcie-rockchip.h +++ b/drivers/pci/controller/pcie-rockchip.h diff --git a/drivers/pci/host/pcie-tango.c b/drivers/pci/controller/pcie-tango.c index 21a208da3f59..21a208da3f59 100644 --- a/drivers/pci/host/pcie-tango.c +++ b/drivers/pci/controller/pcie-tango.c diff --git a/drivers/pci/host/pcie-xilinx-nwl.c b/drivers/pci/controller/pcie-xilinx-nwl.c index 6a4bbb5b3de0..6a4bbb5b3de0 100644 --- a/drivers/pci/host/pcie-xilinx-nwl.c +++ b/drivers/pci/controller/pcie-xilinx-nwl.c diff --git a/drivers/pci/host/pcie-xilinx.c b/drivers/pci/controller/pcie-xilinx.c index b110a3a814e3..b110a3a814e3 100644 --- a/drivers/pci/host/pcie-xilinx.c +++ b/drivers/pci/controller/pcie-xilinx.c diff --git a/drivers/pci/host/vmd.c b/drivers/pci/controller/vmd.c index 942b64fc7f1f..942b64fc7f1f 100644 --- a/drivers/pci/host/vmd.c +++ b/drivers/pci/controller/vmd.c diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index f45b74fcc059..4d88afdfc843 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -474,7 +474,7 @@ static int populate_msi_sysfs(struct pci_dev *pdev) return 0; /* Dynamically create the MSI attributes for the PCI device */ - msi_attrs = kzalloc(sizeof(void *) * (num_msi + 1), GFP_KERNEL); + msi_attrs = kcalloc(num_msi + 1, sizeof(void *), GFP_KERNEL); if (!msi_attrs) return -ENOMEM; for_each_pci_msi_entry(entry, pdev) { @@ -501,7 +501,7 @@ static int populate_msi_sysfs(struct pci_dev *pdev) msi_irq_group->name = "msi_irqs"; msi_irq_group->attrs = msi_attrs; - msi_irq_groups = kzalloc(sizeof(void *) * 2, GFP_KERNEL); + msi_irq_groups = kcalloc(2, sizeof(void *), GFP_KERNEL); if (!msi_irq_groups) goto error_irq_group; msi_irq_groups[0] = msi_irq_group; diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 788a200fb2dc..0c4653c1d2ce 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -1076,7 +1076,7 @@ void pci_create_legacy_files(struct pci_bus *b) { int error; - b->legacy_io = kzalloc(sizeof(struct bin_attribute) * 2, + b->legacy_io = kcalloc(2, sizeof(struct bin_attribute), GFP_ATOMIC); if (!b->legacy_io) goto kzalloc_err; diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig index b12e28b3d8f9..0a1e9d379bc5 100644 --- a/drivers/pci/pcie/Kconfig +++ b/drivers/pci/pcie/Kconfig @@ -23,7 +23,42 @@ config HOTPLUG_PCI_PCIE When in doubt, say N. -source "drivers/pci/pcie/aer/Kconfig" +config PCIEAER + bool "PCI Express Advanced Error Reporting support" + depends on PCIEPORTBUS + select RAS + default y + help + This enables PCI Express Root Port Advanced Error Reporting + (AER) driver support. Error reporting messages sent to Root + Port will be handled by PCI Express AER driver. + +config PCIEAER_INJECT + tristate "PCI Express error injection support" + depends on PCIEAER + default n + help + This enables PCI Express Root Port Advanced Error Reporting + (AER) software error injector. + + Debugging AER code is quite difficult because it is hard + to trigger various real hardware errors. Software-based + error injection can fake almost all kinds of errors with the + help of a user space helper tool aer-inject, which can be + gotten from: + http://www.kernel.org/pub/linux/utils/pci/aer-inject/ + +# +# PCI Express ECRC +# +config PCIE_ECRC + bool "PCI Express ECRC settings control" + depends on PCIEAER + help + Used to override firmware/bios settings for PCI Express ECRC + (transaction layer end-to-end CRC checking). + + When in doubt, say N. # # PCI Express ASPM @@ -92,7 +127,7 @@ config PCIE_PME depends on PCIEPORTBUS && PM config PCIE_DPC - bool "PCIe Downstream Port Containment support" + bool "PCI Express Downstream Port Containment support" depends on PCIEPORTBUS && PCIEAER default n help @@ -103,7 +138,7 @@ config PCIE_DPC it is safe to answer N. config PCIE_PTM - bool "PCIe Precision Time Measurement support" + bool "PCI Express Precision Time Measurement support" default n depends on PCIEPORTBUS help diff --git a/drivers/pci/pcie/Makefile b/drivers/pci/pcie/Makefile index 03f4e0b3a140..ab514083d5d4 100644 --- a/drivers/pci/pcie/Makefile +++ b/drivers/pci/pcie/Makefile @@ -7,7 +7,8 @@ pcieportdrv-y := portdrv_core.o portdrv_pci.o err.o obj-$(CONFIG_PCIEPORTBUS) += pcieportdrv.o obj-$(CONFIG_PCIEASPM) += aspm.o -obj-$(CONFIG_PCIEAER) += aer/ +obj-$(CONFIG_PCIEAER) += aer.o +obj-$(CONFIG_PCIEAER_INJECT) += aer_inject.o obj-$(CONFIG_PCIE_PME) += pme.o obj-$(CONFIG_PCIE_DPC) += dpc.o obj-$(CONFIG_PCIE_PTM) += ptm.o diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c new file mode 100644 index 000000000000..a2e88386af28 --- /dev/null +++ b/drivers/pci/pcie/aer.c @@ -0,0 +1,1377 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Implement the AER root port service driver. The driver registers an IRQ + * handler. When a root port triggers an AER interrupt, the IRQ handler + * collects root port status and schedules work. + * + * Copyright (C) 2006 Intel Corp. + * Tom Long Nguyen (tom.l.nguyen@intel.com) + * Zhang Yanmin (yanmin.zhang@intel.com) + * + * (C) Copyright 2009 Hewlett-Packard Development Company, L.P. + * Andrew Patterson <andrew.patterson@hp.com> + */ + +#include <linux/cper.h> +#include <linux/pci.h> +#include <linux/pci-acpi.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/pm.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/kfifo.h> +#include <linux/slab.h> +#include <acpi/apei.h> +#include <ras/ras_event.h> + +#include "../pci.h" +#include "portdrv.h" + +#define AER_ERROR_SOURCES_MAX 100 +#define AER_MAX_MULTI_ERR_DEVICES 5 /* Not likely to have more */ + +struct aer_err_info { + struct pci_dev *dev[AER_MAX_MULTI_ERR_DEVICES]; + int error_dev_num; + + unsigned int id:16; + + unsigned int severity:2; /* 0:NONFATAL | 1:FATAL | 2:COR */ + unsigned int __pad1:5; + unsigned int multi_error_valid:1; + + unsigned int first_error:5; + unsigned int __pad2:2; + unsigned int tlp_header_valid:1; + + unsigned int status; /* COR/UNCOR Error Status */ + unsigned int mask; /* COR/UNCOR Error Mask */ + struct aer_header_log_regs tlp; /* TLP Header */ +}; + +struct aer_err_source { + unsigned int status; + unsigned int id; +}; + +struct aer_rpc { + struct pci_dev *rpd; /* Root Port device */ + struct work_struct dpc_handler; + struct aer_err_source e_sources[AER_ERROR_SOURCES_MAX]; + struct aer_err_info e_info; + unsigned short prod_idx; /* Error Producer Index */ + unsigned short cons_idx; /* Error Consumer Index */ + int isr; + spinlock_t e_lock; /* + * Lock access to Error Status/ID Regs + * and error producer/consumer index + */ + struct mutex rpc_mutex; /* + * only one thread could do + * recovery on the same + * root port hierarchy + */ +}; + +#define AER_LOG_TLP_MASKS (PCI_ERR_UNC_POISON_TLP| \ + PCI_ERR_UNC_ECRC| \ + PCI_ERR_UNC_UNSUP| \ + PCI_ERR_UNC_COMP_ABORT| \ + PCI_ERR_UNC_UNX_COMP| \ + PCI_ERR_UNC_MALF_TLP) + +#define SYSTEM_ERROR_INTR_ON_MESG_MASK (PCI_EXP_RTCTL_SECEE| \ + PCI_EXP_RTCTL_SENFEE| \ + PCI_EXP_RTCTL_SEFEE) +#define ROOT_PORT_INTR_ON_MESG_MASK (PCI_ERR_ROOT_CMD_COR_EN| \ + PCI_ERR_ROOT_CMD_NONFATAL_EN| \ + PCI_ERR_ROOT_CMD_FATAL_EN) +#define ERR_COR_ID(d) (d & 0xffff) +#define ERR_UNCOR_ID(d) (d >> 16) + +static int pcie_aer_disable; + +void pci_no_aer(void) +{ + pcie_aer_disable = 1; +} + +bool pci_aer_available(void) +{ + return !pcie_aer_disable && pci_msi_enabled(); +} + +#ifdef CONFIG_PCIE_ECRC + +#define ECRC_POLICY_DEFAULT 0 /* ECRC set by BIOS */ +#define ECRC_POLICY_OFF 1 /* ECRC off for performance */ +#define ECRC_POLICY_ON 2 /* ECRC on for data integrity */ + +static int ecrc_policy = ECRC_POLICY_DEFAULT; + +static const char *ecrc_policy_str[] = { + [ECRC_POLICY_DEFAULT] = "bios", + [ECRC_POLICY_OFF] = "off", + [ECRC_POLICY_ON] = "on" +}; + +/** + * enable_ercr_checking - enable PCIe ECRC checking for a device + * @dev: the PCI device + * + * Returns 0 on success, or negative on failure. + */ +static int enable_ecrc_checking(struct pci_dev *dev) +{ + int pos; + u32 reg32; + + if (!pci_is_pcie(dev)) + return -ENODEV; + + pos = dev->aer_cap; + if (!pos) + return -ENODEV; + + pci_read_config_dword(dev, pos + PCI_ERR_CAP, ®32); + if (reg32 & PCI_ERR_CAP_ECRC_GENC) + reg32 |= PCI_ERR_CAP_ECRC_GENE; + if (reg32 & PCI_ERR_CAP_ECRC_CHKC) + reg32 |= PCI_ERR_CAP_ECRC_CHKE; + pci_write_config_dword(dev, pos + PCI_ERR_CAP, reg32); + + return 0; +} + +/** + * disable_ercr_checking - disables PCIe ECRC checking for a device + * @dev: the PCI device + * + * Returns 0 on success, or negative on failure. + */ +static int disable_ecrc_checking(struct pci_dev *dev) +{ + int pos; + u32 reg32; + + if (!pci_is_pcie(dev)) + return -ENODEV; + + pos = dev->aer_cap; + if (!pos) + return -ENODEV; + + pci_read_config_dword(dev, pos + PCI_ERR_CAP, ®32); + reg32 &= ~(PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE); + pci_write_config_dword(dev, pos + PCI_ERR_CAP, reg32); + + return 0; +} + +/** + * pcie_set_ecrc_checking - set/unset PCIe ECRC checking for a device based on global policy + * @dev: the PCI device + */ +void pcie_set_ecrc_checking(struct pci_dev *dev) +{ + switch (ecrc_policy) { + case ECRC_POLICY_DEFAULT: + return; + case ECRC_POLICY_OFF: + disable_ecrc_checking(dev); + break; + case ECRC_POLICY_ON: + enable_ecrc_checking(dev); + break; + default: + return; + } +} + +/** + * pcie_ecrc_get_policy - parse kernel command-line ecrc option + */ +void pcie_ecrc_get_policy(char *str) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ecrc_policy_str); i++) + if (!strncmp(str, ecrc_policy_str[i], + strlen(ecrc_policy_str[i]))) + break; + if (i >= ARRAY_SIZE(ecrc_policy_str)) + return; + + ecrc_policy = i; +} +#endif /* CONFIG_PCIE_ECRC */ + +#ifdef CONFIG_ACPI_APEI +static inline int hest_match_pci(struct acpi_hest_aer_common *p, + struct pci_dev *pci) +{ + return ACPI_HEST_SEGMENT(p->bus) == pci_domain_nr(pci->bus) && + ACPI_HEST_BUS(p->bus) == pci->bus->number && + p->device == PCI_SLOT(pci->devfn) && + p->function == PCI_FUNC(pci->devfn); +} + +static inline bool hest_match_type(struct acpi_hest_header *hest_hdr, + struct pci_dev *dev) +{ + u16 hest_type = hest_hdr->type; + u8 pcie_type = pci_pcie_type(dev); + + if ((hest_type == ACPI_HEST_TYPE_AER_ROOT_PORT && + pcie_type == PCI_EXP_TYPE_ROOT_PORT) || + (hest_type == ACPI_HEST_TYPE_AER_ENDPOINT && + pcie_type == PCI_EXP_TYPE_ENDPOINT) || + (hest_type == ACPI_HEST_TYPE_AER_BRIDGE && + (dev->class >> 16) == PCI_BASE_CLASS_BRIDGE)) + return true; + return false; +} + +struct aer_hest_parse_info { + struct pci_dev *pci_dev; + int firmware_first; +}; + +static int hest_source_is_pcie_aer(struct acpi_hest_header *hest_hdr) +{ + if (hest_hdr->type == ACPI_HEST_TYPE_AER_ROOT_PORT || + hest_hdr->type == ACPI_HEST_TYPE_AER_ENDPOINT || + hest_hdr->type == ACPI_HEST_TYPE_AER_BRIDGE) + return 1; + return 0; +} + +static int aer_hest_parse(struct acpi_hest_header *hest_hdr, void *data) +{ + struct aer_hest_parse_info *info = data; + struct acpi_hest_aer_common *p; + int ff; + + if (!hest_source_is_pcie_aer(hest_hdr)) + return 0; + + p = (struct acpi_hest_aer_common *)(hest_hdr + 1); + ff = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST); + + /* + * If no specific device is supplied, determine whether + * FIRMWARE_FIRST is set for *any* PCIe device. + */ + if (!info->pci_dev) { + info->firmware_first |= ff; + return 0; + } + + /* Otherwise, check the specific device */ + if (p->flags & ACPI_HEST_GLOBAL) { + if (hest_match_type(hest_hdr, info->pci_dev)) + info->firmware_first = ff; + } else + if (hest_match_pci(p, info->pci_dev)) + info->firmware_first = ff; + + return 0; +} + +static void aer_set_firmware_first(struct pci_dev *pci_dev) +{ + int rc; + struct aer_hest_parse_info info = { + .pci_dev = pci_dev, + .firmware_first = 0, + }; + + rc = apei_hest_parse(aer_hest_parse, &info); + + if (rc) + pci_dev->__aer_firmware_first = 0; + else + pci_dev->__aer_firmware_first = info.firmware_first; + pci_dev->__aer_firmware_first_valid = 1; +} + +int pcie_aer_get_firmware_first(struct pci_dev *dev) +{ + if (!pci_is_pcie(dev)) + return 0; + + if (!dev->__aer_firmware_first_valid) + aer_set_firmware_first(dev); + return dev->__aer_firmware_first; +} +#define PCI_EXP_AER_FLAGS (PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | \ + PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE) + +static bool aer_firmware_first; + +/** + * aer_acpi_firmware_first - Check if APEI should control AER. + */ +bool aer_acpi_firmware_first(void) +{ + static bool parsed = false; + struct aer_hest_parse_info info = { + .pci_dev = NULL, /* Check all PCIe devices */ + .firmware_first = 0, + }; + + if (!parsed) { + apei_hest_parse(aer_hest_parse, &info); + aer_firmware_first = info.firmware_first; + parsed = true; + } + return aer_firmware_first; +} +#endif + +#define PCI_EXP_AER_FLAGS (PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | \ + PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE) + +int pci_enable_pcie_error_reporting(struct pci_dev *dev) +{ + if (pcie_aer_get_firmware_first(dev)) + return -EIO; + + if (!dev->aer_cap) + return -EIO; + + return pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_AER_FLAGS); +} +EXPORT_SYMBOL_GPL(pci_enable_pcie_error_reporting); + +int pci_disable_pcie_error_reporting(struct pci_dev *dev) +{ + if (pcie_aer_get_firmware_first(dev)) + return -EIO; + + return pcie_capability_clear_word(dev, PCI_EXP_DEVCTL, + PCI_EXP_AER_FLAGS); +} +EXPORT_SYMBOL_GPL(pci_disable_pcie_error_reporting); + +int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev) +{ + int pos; + u32 status; + + pos = dev->aer_cap; + if (!pos) + return -EIO; + + pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status); + if (status) + pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status); + + return 0; +} +EXPORT_SYMBOL_GPL(pci_cleanup_aer_uncorrect_error_status); + +int pci_cleanup_aer_error_status_regs(struct pci_dev *dev) +{ + int pos; + u32 status; + int port_type; + + if (!pci_is_pcie(dev)) + return -ENODEV; + + pos = dev->aer_cap; + if (!pos) + return -EIO; + + port_type = pci_pcie_type(dev); + if (port_type == PCI_EXP_TYPE_ROOT_PORT) { + pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &status); + pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, status); + } + + pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, &status); + pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS, status); + + pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status); + pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status); + + return 0; +} + +int pci_aer_init(struct pci_dev *dev) +{ + dev->aer_cap = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); + return pci_cleanup_aer_error_status_regs(dev); +} + +#define AER_AGENT_RECEIVER 0 +#define AER_AGENT_REQUESTER 1 +#define AER_AGENT_COMPLETER 2 +#define AER_AGENT_TRANSMITTER 3 + +#define AER_AGENT_REQUESTER_MASK(t) ((t == AER_CORRECTABLE) ? \ + 0 : (PCI_ERR_UNC_COMP_TIME|PCI_ERR_UNC_UNSUP)) +#define AER_AGENT_COMPLETER_MASK(t) ((t == AER_CORRECTABLE) ? \ + 0 : PCI_ERR_UNC_COMP_ABORT) +#define AER_AGENT_TRANSMITTER_MASK(t) ((t == AER_CORRECTABLE) ? \ + (PCI_ERR_COR_REP_ROLL|PCI_ERR_COR_REP_TIMER) : 0) + +#define AER_GET_AGENT(t, e) \ + ((e & AER_AGENT_COMPLETER_MASK(t)) ? AER_AGENT_COMPLETER : \ + (e & AER_AGENT_REQUESTER_MASK(t)) ? AER_AGENT_REQUESTER : \ + (e & AER_AGENT_TRANSMITTER_MASK(t)) ? AER_AGENT_TRANSMITTER : \ + AER_AGENT_RECEIVER) + +#define AER_PHYSICAL_LAYER_ERROR 0 +#define AER_DATA_LINK_LAYER_ERROR 1 +#define AER_TRANSACTION_LAYER_ERROR 2 + +#define AER_PHYSICAL_LAYER_ERROR_MASK(t) ((t == AER_CORRECTABLE) ? \ + PCI_ERR_COR_RCVR : 0) +#define AER_DATA_LINK_LAYER_ERROR_MASK(t) ((t == AER_CORRECTABLE) ? \ + (PCI_ERR_COR_BAD_TLP| \ + PCI_ERR_COR_BAD_DLLP| \ + PCI_ERR_COR_REP_ROLL| \ + PCI_ERR_COR_REP_TIMER) : PCI_ERR_UNC_DLP) + +#define AER_GET_LAYER_ERROR(t, e) \ + ((e & AER_PHYSICAL_LAYER_ERROR_MASK(t)) ? AER_PHYSICAL_LAYER_ERROR : \ + (e & AER_DATA_LINK_LAYER_ERROR_MASK(t)) ? AER_DATA_LINK_LAYER_ERROR : \ + AER_TRANSACTION_LAYER_ERROR) + +/* + * AER error strings + */ +static const char *aer_error_severity_string[] = { + "Uncorrected (Non-Fatal)", + "Uncorrected (Fatal)", + "Corrected" +}; + +static const char *aer_error_layer[] = { + "Physical Layer", + "Data Link Layer", + "Transaction Layer" +}; + +static const char *aer_correctable_error_string[] = { + "Receiver Error", /* Bit Position 0 */ + NULL, + NULL, + NULL, + NULL, + NULL, + "Bad TLP", /* Bit Position 6 */ + "Bad DLLP", /* Bit Position 7 */ + "RELAY_NUM Rollover", /* Bit Position 8 */ + NULL, + NULL, + NULL, + "Replay Timer Timeout", /* Bit Position 12 */ + "Advisory Non-Fatal", /* Bit Position 13 */ + "Corrected Internal Error", /* Bit Position 14 */ + "Header Log Overflow", /* Bit Position 15 */ +}; + +static const char *aer_uncorrectable_error_string[] = { + "Undefined", /* Bit Position 0 */ + NULL, + NULL, + NULL, + "Data Link Protocol", /* Bit Position 4 */ + "Surprise Down Error", /* Bit Position 5 */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "Poisoned TLP", /* Bit Position 12 */ + "Flow Control Protocol", /* Bit Position 13 */ + "Completion Timeout", /* Bit Position 14 */ + "Completer Abort", /* Bit Position 15 */ + "Unexpected Completion", /* Bit Position 16 */ + "Receiver Overflow", /* Bit Position 17 */ + "Malformed TLP", /* Bit Position 18 */ + "ECRC", /* Bit Position 19 */ + "Unsupported Request", /* Bit Position 20 */ + "ACS Violation", /* Bit Position 21 */ + "Uncorrectable Internal Error", /* Bit Position 22 */ + "MC Blocked TLP", /* Bit Position 23 */ + "AtomicOp Egress Blocked", /* Bit Position 24 */ + "TLP Prefix Blocked Error", /* Bit Position 25 */ +}; + +static const char *aer_agent_string[] = { + "Receiver ID", + "Requester ID", + "Completer ID", + "Transmitter ID" +}; + +static void __print_tlp_header(struct pci_dev *dev, + struct aer_header_log_regs *t) +{ + pci_err(dev, " TLP Header: %08x %08x %08x %08x\n", + t->dw0, t->dw1, t->dw2, t->dw3); +} + +static void __aer_print_error(struct pci_dev *dev, + struct aer_err_info *info) +{ + int i, status; + const char *errmsg = NULL; + status = (info->status & ~info->mask); + + for (i = 0; i < 32; i++) { + if (!(status & (1 << i))) + continue; + + if (info->severity == AER_CORRECTABLE) + errmsg = i < ARRAY_SIZE(aer_correctable_error_string) ? + aer_correctable_error_string[i] : NULL; + else + errmsg = i < ARRAY_SIZE(aer_uncorrectable_error_string) ? + aer_uncorrectable_error_string[i] : NULL; + + if (errmsg) + pci_err(dev, " [%2d] %-22s%s\n", i, errmsg, + info->first_error == i ? " (First)" : ""); + else + pci_err(dev, " [%2d] Unknown Error Bit%s\n", + i, info->first_error == i ? " (First)" : ""); + } +} + +static void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) +{ + int layer, agent; + int id = ((dev->bus->number << 8) | dev->devfn); + + if (!info->status) { + pci_err(dev, "PCIe Bus Error: severity=%s, type=Inaccessible, (Unregistered Agent ID)\n", + aer_error_severity_string[info->severity]); + goto out; + } + + layer = AER_GET_LAYER_ERROR(info->severity, info->status); + agent = AER_GET_AGENT(info->severity, info->status); + + pci_err(dev, "PCIe Bus Error: severity=%s, type=%s, (%s)\n", + aer_error_severity_string[info->severity], + aer_error_layer[layer], aer_agent_string[agent]); + + pci_err(dev, " device [%04x:%04x] error status/mask=%08x/%08x\n", + dev->vendor, dev->device, + info->status, info->mask); + + __aer_print_error(dev, info); + + if (info->tlp_header_valid) + __print_tlp_header(dev, &info->tlp); + +out: + if (info->id && info->error_dev_num > 1 && info->id == id) + pci_err(dev, " Error of this Agent is reported first\n"); + + trace_aer_event(dev_name(&dev->dev), (info->status & ~info->mask), + info->severity, info->tlp_header_valid, &info->tlp); +} + +static void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info) +{ + u8 bus = info->id >> 8; + u8 devfn = info->id & 0xff; + + pci_info(dev, "AER: %s%s error received: %04x:%02x:%02x.%d\n", + info->multi_error_valid ? "Multiple " : "", + aer_error_severity_string[info->severity], + pci_domain_nr(dev->bus), bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); +} + +#ifdef CONFIG_ACPI_APEI_PCIEAER +int cper_severity_to_aer(int cper_severity) +{ + switch (cper_severity) { + case CPER_SEV_RECOVERABLE: + return AER_NONFATAL; + case CPER_SEV_FATAL: + return AER_FATAL; + default: + return AER_CORRECTABLE; + } +} +EXPORT_SYMBOL_GPL(cper_severity_to_aer); + +void cper_print_aer(struct pci_dev *dev, int aer_severity, + struct aer_capability_regs *aer) +{ + int layer, agent, tlp_header_valid = 0; + u32 status, mask; + struct aer_err_info info; + + if (aer_severity == AER_CORRECTABLE) { + status = aer->cor_status; + mask = aer->cor_mask; + } else { + status = aer->uncor_status; + mask = aer->uncor_mask; + tlp_header_valid = status & AER_LOG_TLP_MASKS; + } + + layer = AER_GET_LAYER_ERROR(aer_severity, status); + agent = AER_GET_AGENT(aer_severity, status); + + memset(&info, 0, sizeof(info)); + info.severity = aer_severity; + info.status = status; + info.mask = mask; + info.first_error = PCI_ERR_CAP_FEP(aer->cap_control); + + pci_err(dev, "aer_status: 0x%08x, aer_mask: 0x%08x\n", status, mask); + __aer_print_error(dev, &info); + pci_err(dev, "aer_layer=%s, aer_agent=%s\n", + aer_error_layer[layer], aer_agent_string[agent]); + + if (aer_severity != AER_CORRECTABLE) + pci_err(dev, "aer_uncor_severity: 0x%08x\n", + aer->uncor_severity); + + if (tlp_header_valid) + __print_tlp_header(dev, &aer->header_log); + + trace_aer_event(dev_name(&dev->dev), (status & ~mask), + aer_severity, tlp_header_valid, &aer->header_log); +} +#endif + +/** + * add_error_device - list device to be handled + * @e_info: pointer to error info + * @dev: pointer to pci_dev to be added + */ +static int add_error_device(struct aer_err_info *e_info, struct pci_dev *dev) +{ + if (e_info->error_dev_num < AER_MAX_MULTI_ERR_DEVICES) { + e_info->dev[e_info->error_dev_num] = dev; + e_info->error_dev_num++; + return 0; + } + return -ENOSPC; +} + +/** + * is_error_source - check whether the device is source of reported error + * @dev: pointer to pci_dev to be checked + * @e_info: pointer to reported error info + */ +static bool is_error_source(struct pci_dev *dev, struct aer_err_info *e_info) +{ + int pos; + u32 status, mask; + u16 reg16; + + /* + * When bus id is equal to 0, it might be a bad id + * reported by root port. + */ + if ((PCI_BUS_NUM(e_info->id) != 0) && + !(dev->bus->bus_flags & PCI_BUS_FLAGS_NO_AERSID)) { + /* Device ID match? */ + if (e_info->id == ((dev->bus->number << 8) | dev->devfn)) + return true; + + /* Continue id comparing if there is no multiple error */ + if (!e_info->multi_error_valid) + return false; + } + + /* + * When either + * 1) bus id is equal to 0. Some ports might lose the bus + * id of error source id; + * 2) bus flag PCI_BUS_FLAGS_NO_AERSID is set + * 3) There are multiple errors and prior ID comparing fails; + * We check AER status registers to find possible reporter. + */ + if (atomic_read(&dev->enable_cnt) == 0) + return false; + + /* Check if AER is enabled */ + pcie_capability_read_word(dev, PCI_EXP_DEVCTL, ®16); + if (!(reg16 & PCI_EXP_AER_FLAGS)) + return false; + + pos = dev->aer_cap; + if (!pos) + return false; + + /* Check if error is recorded */ + if (e_info->severity == AER_CORRECTABLE) { + pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, &status); + pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, &mask); + } else { + pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status); + pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, &mask); + } + if (status & ~mask) + return true; + + return false; +} + +static int find_device_iter(struct pci_dev *dev, void *data) +{ + struct aer_err_info *e_info = (struct aer_err_info *)data; + + if (is_error_source(dev, e_info)) { + /* List this device */ + if (add_error_device(e_info, dev)) { + /* We cannot handle more... Stop iteration */ + /* TODO: Should print error message here? */ + return 1; + } + + /* If there is only a single error, stop iteration */ + if (!e_info->multi_error_valid) + return 1; + } + return 0; +} + +/** + * find_source_device - search through device hierarchy for source device + * @parent: pointer to Root Port pci_dev data structure + * @e_info: including detailed error information such like id + * + * Return true if found. + * + * Invoked by DPC when error is detected at the Root Port. + * Caller of this function must set id, severity, and multi_error_valid of + * struct aer_err_info pointed by @e_info properly. This function must fill + * e_info->error_dev_num and e_info->dev[], based on the given information. + */ +static bool find_source_device(struct pci_dev *parent, + struct aer_err_info *e_info) +{ + struct pci_dev *dev = parent; + int result; + + /* Must reset in this function */ + e_info->error_dev_num = 0; + + /* Is Root Port an agent that sends error message? */ + result = find_device_iter(dev, e_info); + if (result) + return true; + + pci_walk_bus(parent->subordinate, find_device_iter, e_info); + + if (!e_info->error_dev_num) { + pci_printk(KERN_DEBUG, parent, "can't find device of ID%04x\n", + e_info->id); + return false; + } + return true; +} + +/** + * handle_error_source - handle logging error into an event log + * @dev: pointer to pci_dev data structure of error source device + * @info: comprehensive error information + * + * Invoked when an error being detected by Root Port. + */ +static void handle_error_source(struct pci_dev *dev, struct aer_err_info *info) +{ + int pos; + + if (info->severity == AER_CORRECTABLE) { + /* + * Correctable error does not need software intervention. + * No need to go through error recovery process. + */ + pos = dev->aer_cap; + if (pos) + pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS, + info->status); + } else if (info->severity == AER_NONFATAL) + pcie_do_nonfatal_recovery(dev); + else if (info->severity == AER_FATAL) + pcie_do_fatal_recovery(dev, PCIE_PORT_SERVICE_AER); +} + +#ifdef CONFIG_ACPI_APEI_PCIEAER + +#define AER_RECOVER_RING_ORDER 4 +#define AER_RECOVER_RING_SIZE (1 << AER_RECOVER_RING_ORDER) + +struct aer_recover_entry { + u8 bus; + u8 devfn; + u16 domain; + int severity; + struct aer_capability_regs *regs; +}; + +static DEFINE_KFIFO(aer_recover_ring, struct aer_recover_entry, + AER_RECOVER_RING_SIZE); + +static void aer_recover_work_func(struct work_struct *work) +{ + struct aer_recover_entry entry; + struct pci_dev *pdev; + + while (kfifo_get(&aer_recover_ring, &entry)) { + pdev = pci_get_domain_bus_and_slot(entry.domain, entry.bus, + entry.devfn); + if (!pdev) { + pr_err("AER recover: Can not find pci_dev for %04x:%02x:%02x:%x\n", + entry.domain, entry.bus, + PCI_SLOT(entry.devfn), PCI_FUNC(entry.devfn)); + continue; + } + cper_print_aer(pdev, entry.severity, entry.regs); + if (entry.severity == AER_NONFATAL) + pcie_do_nonfatal_recovery(pdev); + else if (entry.severity == AER_FATAL) + pcie_do_fatal_recovery(pdev, PCIE_PORT_SERVICE_AER); + pci_dev_put(pdev); + } +} + +/* + * Mutual exclusion for writers of aer_recover_ring, reader side don't + * need lock, because there is only one reader and lock is not needed + * between reader and writer. + */ +static DEFINE_SPINLOCK(aer_recover_ring_lock); +static DECLARE_WORK(aer_recover_work, aer_recover_work_func); + +void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn, + int severity, struct aer_capability_regs *aer_regs) +{ + unsigned long flags; + struct aer_recover_entry entry = { + .bus = bus, + .devfn = devfn, + .domain = domain, + .severity = severity, + .regs = aer_regs, + }; + + spin_lock_irqsave(&aer_recover_ring_lock, flags); + if (kfifo_put(&aer_recover_ring, entry)) + schedule_work(&aer_recover_work); + else + pr_err("AER recover: Buffer overflow when recovering AER for %04x:%02x:%02x:%x\n", + domain, bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); + spin_unlock_irqrestore(&aer_recover_ring_lock, flags); +} +EXPORT_SYMBOL_GPL(aer_recover_queue); +#endif + +/** + * get_device_error_info - read error status from dev and store it to info + * @dev: pointer to the device expected to have a error record + * @info: pointer to structure to store the error record + * + * Return 1 on success, 0 on error. + * + * Note that @info is reused among all error devices. Clear fields properly. + */ +static int get_device_error_info(struct pci_dev *dev, struct aer_err_info *info) +{ + int pos, temp; + + /* Must reset in this function */ + info->status = 0; + info->tlp_header_valid = 0; + + pos = dev->aer_cap; + + /* The device might not support AER */ + if (!pos) + return 0; + + if (info->severity == AER_CORRECTABLE) { + pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, + &info->status); + pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, + &info->mask); + if (!(info->status & ~info->mask)) + return 0; + } else if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || + info->severity == AER_NONFATAL) { + + /* Link is still healthy for IO reads */ + pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, + &info->status); + pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, + &info->mask); + if (!(info->status & ~info->mask)) + return 0; + + /* Get First Error Pointer */ + pci_read_config_dword(dev, pos + PCI_ERR_CAP, &temp); + info->first_error = PCI_ERR_CAP_FEP(temp); + + if (info->status & AER_LOG_TLP_MASKS) { + info->tlp_header_valid = 1; + pci_read_config_dword(dev, + pos + PCI_ERR_HEADER_LOG, &info->tlp.dw0); + pci_read_config_dword(dev, + pos + PCI_ERR_HEADER_LOG + 4, &info->tlp.dw1); + pci_read_config_dword(dev, + pos + PCI_ERR_HEADER_LOG + 8, &info->tlp.dw2); + pci_read_config_dword(dev, + pos + PCI_ERR_HEADER_LOG + 12, &info->tlp.dw3); + } + } + + return 1; +} + +static inline void aer_process_err_devices(struct aer_err_info *e_info) +{ + int i; + + /* Report all before handle them, not to lost records by reset etc. */ + for (i = 0; i < e_info->error_dev_num && e_info->dev[i]; i++) { + if (get_device_error_info(e_info->dev[i], e_info)) + aer_print_error(e_info->dev[i], e_info); + } + for (i = 0; i < e_info->error_dev_num && e_info->dev[i]; i++) { + if (get_device_error_info(e_info->dev[i], e_info)) + handle_error_source(e_info->dev[i], e_info); + } +} + +/** + * aer_isr_one_error - consume an error detected by root port + * @rpc: pointer to the root port which holds an error + * @e_src: pointer to an error source + */ +static void aer_isr_one_error(struct aer_rpc *rpc, + struct aer_err_source *e_src) +{ + struct pci_dev *pdev = rpc->rpd; + struct aer_err_info *e_info = &rpc->e_info; + + /* + * There is a possibility that both correctable error and + * uncorrectable error being logged. Report correctable error first. + */ + if (e_src->status & PCI_ERR_ROOT_COR_RCV) { + e_info->id = ERR_COR_ID(e_src->id); + e_info->severity = AER_CORRECTABLE; + + if (e_src->status & PCI_ERR_ROOT_MULTI_COR_RCV) + e_info->multi_error_valid = 1; + else + e_info->multi_error_valid = 0; + aer_print_port_info(pdev, e_info); + + if (find_source_device(pdev, e_info)) + aer_process_err_devices(e_info); + } + + if (e_src->status & PCI_ERR_ROOT_UNCOR_RCV) { + e_info->id = ERR_UNCOR_ID(e_src->id); + + if (e_src->status & PCI_ERR_ROOT_FATAL_RCV) + e_info->severity = AER_FATAL; + else + e_info->severity = AER_NONFATAL; + + if (e_src->status & PCI_ERR_ROOT_MULTI_UNCOR_RCV) + e_info->multi_error_valid = 1; + else + e_info->multi_error_valid = 0; + + aer_print_port_info(pdev, e_info); + + if (find_source_device(pdev, e_info)) + aer_process_err_devices(e_info); + } +} + +/** + * get_e_source - retrieve an error source + * @rpc: pointer to the root port which holds an error + * @e_src: pointer to store retrieved error source + * + * Return 1 if an error source is retrieved, otherwise 0. + * + * Invoked by DPC handler to consume an error. + */ +static int get_e_source(struct aer_rpc *rpc, struct aer_err_source *e_src) +{ + unsigned long flags; + + /* Lock access to Root error producer/consumer index */ + spin_lock_irqsave(&rpc->e_lock, flags); + if (rpc->prod_idx == rpc->cons_idx) { + spin_unlock_irqrestore(&rpc->e_lock, flags); + return 0; + } + + *e_src = rpc->e_sources[rpc->cons_idx]; + rpc->cons_idx++; + if (rpc->cons_idx == AER_ERROR_SOURCES_MAX) + rpc->cons_idx = 0; + spin_unlock_irqrestore(&rpc->e_lock, flags); + + return 1; +} + +/** + * aer_isr - consume errors detected by root port + * @work: definition of this work item + * + * Invoked, as DPC, when root port records new detected error + */ +static void aer_isr(struct work_struct *work) +{ + struct aer_rpc *rpc = container_of(work, struct aer_rpc, dpc_handler); + struct aer_err_source uninitialized_var(e_src); + + mutex_lock(&rpc->rpc_mutex); + while (get_e_source(rpc, &e_src)) + aer_isr_one_error(rpc, &e_src); + mutex_unlock(&rpc->rpc_mutex); +} + +/** + * aer_irq - Root Port's ISR + * @irq: IRQ assigned to Root Port + * @context: pointer to Root Port data structure + * + * Invoked when Root Port detects AER messages. + */ +irqreturn_t aer_irq(int irq, void *context) +{ + unsigned int status, id; + struct pcie_device *pdev = (struct pcie_device *)context; + struct aer_rpc *rpc = get_service_data(pdev); + int next_prod_idx; + unsigned long flags; + int pos; + + pos = pdev->port->aer_cap; + /* + * Must lock access to Root Error Status Reg, Root Error ID Reg, + * and Root error producer/consumer index + */ + spin_lock_irqsave(&rpc->e_lock, flags); + + /* Read error status */ + pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, &status); + if (!(status & (PCI_ERR_ROOT_UNCOR_RCV|PCI_ERR_ROOT_COR_RCV))) { + spin_unlock_irqrestore(&rpc->e_lock, flags); + return IRQ_NONE; + } + + /* Read error source and clear error status */ + pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_ERR_SRC, &id); + pci_write_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, status); + + /* Store error source for later DPC handler */ + next_prod_idx = rpc->prod_idx + 1; + if (next_prod_idx == AER_ERROR_SOURCES_MAX) + next_prod_idx = 0; + if (next_prod_idx == rpc->cons_idx) { + /* + * Error Storm Condition - possibly the same error occurred. + * Drop the error. + */ + spin_unlock_irqrestore(&rpc->e_lock, flags); + return IRQ_HANDLED; + } + rpc->e_sources[rpc->prod_idx].status = status; + rpc->e_sources[rpc->prod_idx].id = id; + rpc->prod_idx = next_prod_idx; + spin_unlock_irqrestore(&rpc->e_lock, flags); + + /* Invoke DPC handler */ + schedule_work(&rpc->dpc_handler); + + return IRQ_HANDLED; +} +EXPORT_SYMBOL_GPL(aer_irq); + +static int set_device_error_reporting(struct pci_dev *dev, void *data) +{ + bool enable = *((bool *)data); + int type = pci_pcie_type(dev); + + if ((type == PCI_EXP_TYPE_ROOT_PORT) || + (type == PCI_EXP_TYPE_UPSTREAM) || + (type == PCI_EXP_TYPE_DOWNSTREAM)) { + if (enable) + pci_enable_pcie_error_reporting(dev); + else + pci_disable_pcie_error_reporting(dev); + } + + if (enable) + pcie_set_ecrc_checking(dev); + + return 0; +} + +/** + * set_downstream_devices_error_reporting - enable/disable the error reporting bits on the root port and its downstream ports. + * @dev: pointer to root port's pci_dev data structure + * @enable: true = enable error reporting, false = disable error reporting. + */ +static void set_downstream_devices_error_reporting(struct pci_dev *dev, + bool enable) +{ + set_device_error_reporting(dev, &enable); + + if (!dev->subordinate) + return; + pci_walk_bus(dev->subordinate, set_device_error_reporting, &enable); +} + +/** + * aer_enable_rootport - enable Root Port's interrupts when receiving messages + * @rpc: pointer to a Root Port data structure + * + * Invoked when PCIe bus loads AER service driver. + */ +static void aer_enable_rootport(struct aer_rpc *rpc) +{ + struct pci_dev *pdev = rpc->rpd; + int aer_pos; + u16 reg16; + u32 reg32; + + /* Clear PCIe Capability's Device Status */ + pcie_capability_read_word(pdev, PCI_EXP_DEVSTA, ®16); + pcie_capability_write_word(pdev, PCI_EXP_DEVSTA, reg16); + + /* Disable system error generation in response to error messages */ + pcie_capability_clear_word(pdev, PCI_EXP_RTCTL, + SYSTEM_ERROR_INTR_ON_MESG_MASK); + + aer_pos = pdev->aer_cap; + /* Clear error status */ + pci_read_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, ®32); + pci_write_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, reg32); + pci_read_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, ®32); + pci_write_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, reg32); + pci_read_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, ®32); + pci_write_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, reg32); + + /* + * Enable error reporting for the root port device and downstream port + * devices. + */ + set_downstream_devices_error_reporting(pdev, true); + + /* Enable Root Port's interrupt in response to error messages */ + pci_read_config_dword(pdev, aer_pos + PCI_ERR_ROOT_COMMAND, ®32); + reg32 |= ROOT_PORT_INTR_ON_MESG_MASK; + pci_write_config_dword(pdev, aer_pos + PCI_ERR_ROOT_COMMAND, reg32); +} + +/** + * aer_disable_rootport - disable Root Port's interrupts when receiving messages + * @rpc: pointer to a Root Port data structure + * + * Invoked when PCIe bus unloads AER service driver. + */ +static void aer_disable_rootport(struct aer_rpc *rpc) +{ + struct pci_dev *pdev = rpc->rpd; + u32 reg32; + int pos; + + /* + * Disable error reporting for the root port device and downstream port + * devices. + */ + set_downstream_devices_error_reporting(pdev, false); + + pos = pdev->aer_cap; + /* Disable Root's interrupt in response to error messages */ + pci_read_config_dword(pdev, pos + PCI_ERR_ROOT_COMMAND, ®32); + reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK; + pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_COMMAND, reg32); + + /* Clear Root's error status reg */ + pci_read_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, ®32); + pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, reg32); +} + +/** + * aer_alloc_rpc - allocate Root Port data structure + * @dev: pointer to the pcie_dev data structure + * + * Invoked when Root Port's AER service is loaded. + */ +static struct aer_rpc *aer_alloc_rpc(struct pcie_device *dev) +{ + struct aer_rpc *rpc; + + rpc = kzalloc(sizeof(struct aer_rpc), GFP_KERNEL); + if (!rpc) + return NULL; + + /* Initialize Root lock access, e_lock, to Root Error Status Reg */ + spin_lock_init(&rpc->e_lock); + + rpc->rpd = dev->port; + INIT_WORK(&rpc->dpc_handler, aer_isr); + mutex_init(&rpc->rpc_mutex); + + /* Use PCIe bus function to store rpc into PCIe device */ + set_service_data(dev, rpc); + + return rpc; +} + +/** + * aer_remove - clean up resources + * @dev: pointer to the pcie_dev data structure + * + * Invoked when PCI Express bus unloads or AER probe fails. + */ +static void aer_remove(struct pcie_device *dev) +{ + struct aer_rpc *rpc = get_service_data(dev); + + if (rpc) { + /* If register interrupt service, it must be free. */ + if (rpc->isr) + free_irq(dev->irq, dev); + + flush_work(&rpc->dpc_handler); + aer_disable_rootport(rpc); + kfree(rpc); + set_service_data(dev, NULL); + } +} + +/** + * aer_probe - initialize resources + * @dev: pointer to the pcie_dev data structure + * + * Invoked when PCI Express bus loads AER service driver. + */ +static int aer_probe(struct pcie_device *dev) +{ + int status; + struct aer_rpc *rpc; + struct device *device = &dev->port->dev; + + /* Alloc rpc data structure */ + rpc = aer_alloc_rpc(dev); + if (!rpc) { + dev_printk(KERN_DEBUG, device, "alloc AER rpc failed\n"); + aer_remove(dev); + return -ENOMEM; + } + + /* Request IRQ ISR */ + status = request_irq(dev->irq, aer_irq, IRQF_SHARED, "aerdrv", dev); + if (status) { + dev_printk(KERN_DEBUG, device, "request AER IRQ %d failed\n", + dev->irq); + aer_remove(dev); + return status; + } + + rpc->isr = 1; + + aer_enable_rootport(rpc); + dev_info(device, "AER enabled with IRQ %d\n", dev->irq); + return 0; +} + +/** + * aer_root_reset - reset link on Root Port + * @dev: pointer to Root Port's pci_dev data structure + * + * Invoked by Port Bus driver when performing link reset at Root Port. + */ +static pci_ers_result_t aer_root_reset(struct pci_dev *dev) +{ + u32 reg32; + int pos; + + pos = dev->aer_cap; + + /* Disable Root's interrupt in response to error messages */ + pci_read_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, ®32); + reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK; + pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32); + + pci_reset_bridge_secondary_bus(dev); + pci_printk(KERN_DEBUG, dev, "Root Port link has been reset\n"); + + /* Clear Root Error Status */ + pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, ®32); + pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, reg32); + + /* Enable Root Port's interrupt in response to error messages */ + pci_read_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, ®32); + reg32 |= ROOT_PORT_INTR_ON_MESG_MASK; + pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32); + + return PCI_ERS_RESULT_RECOVERED; +} + +/** + * aer_error_resume - clean up corresponding error status bits + * @dev: pointer to Root Port's pci_dev data structure + * + * Invoked by Port Bus driver during nonfatal recovery. + */ +static void aer_error_resume(struct pci_dev *dev) +{ + int pos; + u32 status, mask; + u16 reg16; + + /* Clean up Root device status */ + pcie_capability_read_word(dev, PCI_EXP_DEVSTA, ®16); + pcie_capability_write_word(dev, PCI_EXP_DEVSTA, reg16); + + /* Clean AER Root Error Status */ + pos = dev->aer_cap; + pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status); + pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &mask); + status &= ~mask; /* Clear corresponding nonfatal bits */ + pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status); +} + +static struct pcie_port_service_driver aerdriver = { + .name = "aer", + .port_type = PCI_EXP_TYPE_ROOT_PORT, + .service = PCIE_PORT_SERVICE_AER, + + .probe = aer_probe, + .remove = aer_remove, + .error_resume = aer_error_resume, + .reset_link = aer_root_reset, +}; + +/** + * aer_service_init - register AER root service driver + * + * Invoked when AER root service driver is loaded. + */ +static int __init aer_service_init(void) +{ + if (!pci_aer_available() || aer_acpi_firmware_first()) + return -ENXIO; + return pcie_port_service_register(&aerdriver); +} +device_initcall(aer_service_init); diff --git a/drivers/pci/pcie/aer/Kconfig b/drivers/pci/pcie/aer/Kconfig deleted file mode 100644 index 5a64eb3d6c7a..000000000000 --- a/drivers/pci/pcie/aer/Kconfig +++ /dev/null @@ -1,29 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# PCI Express Root Port Device AER Configuration -# - -config PCIEAER - bool "Root Port Advanced Error Reporting support" - depends on PCIEPORTBUS - select RAS - default y - help - This enables PCI Express Root Port Advanced Error Reporting - (AER) driver support. Error reporting messages sent to Root - Port will be handled by PCI Express AER driver. - - -# -# PCI Express ECRC -# -config PCIE_ECRC - bool "PCI Express ECRC settings control" - depends on PCIEAER - help - Used to override firmware/bios settings for PCI Express ECRC - (transaction layer end-to-end CRC checking). - - When in doubt, say N. - -source "drivers/pci/pcie/aer/Kconfig.debug" diff --git a/drivers/pci/pcie/aer/Kconfig.debug b/drivers/pci/pcie/aer/Kconfig.debug deleted file mode 100644 index 67e02174b65b..000000000000 --- a/drivers/pci/pcie/aer/Kconfig.debug +++ /dev/null @@ -1,19 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# PCI Express Root Port Device AER Debug Configuration -# - -config PCIEAER_INJECT - tristate "PCIe AER error injector support" - depends on PCIEAER - default n - help - This enables PCI Express Root Port Advanced Error Reporting - (AER) software error injector. - - Debugging PCIe AER code is quite difficult because it is hard - to trigger various real hardware errors. Software based - error injection can fake almost all kinds of errors with the - help of a user space helper tool aer-inject, which can be - gotten from: - http://www.kernel.org/pub/linux/utils/pci/aer-inject/ diff --git a/drivers/pci/pcie/aer/Makefile b/drivers/pci/pcie/aer/Makefile deleted file mode 100644 index 09bd890875a3..000000000000 --- a/drivers/pci/pcie/aer/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for PCI-Express Root Port Advanced Error Reporting Driver -# - -obj-$(CONFIG_PCIEAER) += aerdriver.o - -obj-$(CONFIG_PCIE_ECRC) += ecrc.o - -aerdriver-objs := aerdrv_errprint.o aerdrv_core.o aerdrv.o -aerdriver-$(CONFIG_ACPI) += aerdrv_acpi.o - -obj-$(CONFIG_PCIEAER_INJECT) += aer_inject.o diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c deleted file mode 100644 index 9735c19bf39c..000000000000 --- a/drivers/pci/pcie/aer/aerdrv.c +++ /dev/null @@ -1,371 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Implement the AER root port service driver. The driver registers an IRQ - * handler. When a root port triggers an AER interrupt, the IRQ handler - * collects root port status and schedules work. - * - * Copyright (C) 2006 Intel Corp. - * Tom Long Nguyen (tom.l.nguyen@intel.com) - * Zhang Yanmin (yanmin.zhang@intel.com) - */ - -#include <linux/pci.h> -#include <linux/pci-acpi.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/pm.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/slab.h> - -#include "aerdrv.h" -#include "../../pci.h" - -static int aer_probe(struct pcie_device *dev); -static void aer_remove(struct pcie_device *dev); -static void aer_error_resume(struct pci_dev *dev); -static pci_ers_result_t aer_root_reset(struct pci_dev *dev); - -static struct pcie_port_service_driver aerdriver = { - .name = "aer", - .port_type = PCI_EXP_TYPE_ROOT_PORT, - .service = PCIE_PORT_SERVICE_AER, - - .probe = aer_probe, - .remove = aer_remove, - .error_resume = aer_error_resume, - .reset_link = aer_root_reset, -}; - -static int pcie_aer_disable; - -void pci_no_aer(void) -{ - pcie_aer_disable = 1; -} - -bool pci_aer_available(void) -{ - return !pcie_aer_disable && pci_msi_enabled(); -} - -static int set_device_error_reporting(struct pci_dev *dev, void *data) -{ - bool enable = *((bool *)data); - int type = pci_pcie_type(dev); - - if ((type == PCI_EXP_TYPE_ROOT_PORT) || - (type == PCI_EXP_TYPE_UPSTREAM) || - (type == PCI_EXP_TYPE_DOWNSTREAM)) { - if (enable) - pci_enable_pcie_error_reporting(dev); - else - pci_disable_pcie_error_reporting(dev); - } - - if (enable) - pcie_set_ecrc_checking(dev); - - return 0; -} - -/** - * set_downstream_devices_error_reporting - enable/disable the error reporting bits on the root port and its downstream ports. - * @dev: pointer to root port's pci_dev data structure - * @enable: true = enable error reporting, false = disable error reporting. - */ -static void set_downstream_devices_error_reporting(struct pci_dev *dev, - bool enable) -{ - set_device_error_reporting(dev, &enable); - - if (!dev->subordinate) - return; - pci_walk_bus(dev->subordinate, set_device_error_reporting, &enable); -} - -/** - * aer_enable_rootport - enable Root Port's interrupts when receiving messages - * @rpc: pointer to a Root Port data structure - * - * Invoked when PCIe bus loads AER service driver. - */ -static void aer_enable_rootport(struct aer_rpc *rpc) -{ - struct pci_dev *pdev = rpc->rpd; - int aer_pos; - u16 reg16; - u32 reg32; - - /* Clear PCIe Capability's Device Status */ - pcie_capability_read_word(pdev, PCI_EXP_DEVSTA, ®16); - pcie_capability_write_word(pdev, PCI_EXP_DEVSTA, reg16); - - /* Disable system error generation in response to error messages */ - pcie_capability_clear_word(pdev, PCI_EXP_RTCTL, - SYSTEM_ERROR_INTR_ON_MESG_MASK); - - aer_pos = pdev->aer_cap; - /* Clear error status */ - pci_read_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, ®32); - pci_write_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, reg32); - pci_read_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, ®32); - pci_write_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, reg32); - pci_read_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, ®32); - pci_write_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, reg32); - - /* - * Enable error reporting for the root port device and downstream port - * devices. - */ - set_downstream_devices_error_reporting(pdev, true); - - /* Enable Root Port's interrupt in response to error messages */ - pci_read_config_dword(pdev, aer_pos + PCI_ERR_ROOT_COMMAND, ®32); - reg32 |= ROOT_PORT_INTR_ON_MESG_MASK; - pci_write_config_dword(pdev, aer_pos + PCI_ERR_ROOT_COMMAND, reg32); -} - -/** - * aer_disable_rootport - disable Root Port's interrupts when receiving messages - * @rpc: pointer to a Root Port data structure - * - * Invoked when PCIe bus unloads AER service driver. - */ -static void aer_disable_rootport(struct aer_rpc *rpc) -{ - struct pci_dev *pdev = rpc->rpd; - u32 reg32; - int pos; - - /* - * Disable error reporting for the root port device and downstream port - * devices. - */ - set_downstream_devices_error_reporting(pdev, false); - - pos = pdev->aer_cap; - /* Disable Root's interrupt in response to error messages */ - pci_read_config_dword(pdev, pos + PCI_ERR_ROOT_COMMAND, ®32); - reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK; - pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_COMMAND, reg32); - - /* Clear Root's error status reg */ - pci_read_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, ®32); - pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, reg32); -} - -/** - * aer_irq - Root Port's ISR - * @irq: IRQ assigned to Root Port - * @context: pointer to Root Port data structure - * - * Invoked when Root Port detects AER messages. - */ -irqreturn_t aer_irq(int irq, void *context) -{ - unsigned int status, id; - struct pcie_device *pdev = (struct pcie_device *)context; - struct aer_rpc *rpc = get_service_data(pdev); - int next_prod_idx; - unsigned long flags; - int pos; - - pos = pdev->port->aer_cap; - /* - * Must lock access to Root Error Status Reg, Root Error ID Reg, - * and Root error producer/consumer index - */ - spin_lock_irqsave(&rpc->e_lock, flags); - - /* Read error status */ - pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, &status); - if (!(status & (PCI_ERR_ROOT_UNCOR_RCV|PCI_ERR_ROOT_COR_RCV))) { - spin_unlock_irqrestore(&rpc->e_lock, flags); - return IRQ_NONE; - } - - /* Read error source and clear error status */ - pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_ERR_SRC, &id); - pci_write_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, status); - - /* Store error source for later DPC handler */ - next_prod_idx = rpc->prod_idx + 1; - if (next_prod_idx == AER_ERROR_SOURCES_MAX) - next_prod_idx = 0; - if (next_prod_idx == rpc->cons_idx) { - /* - * Error Storm Condition - possibly the same error occurred. - * Drop the error. - */ - spin_unlock_irqrestore(&rpc->e_lock, flags); - return IRQ_HANDLED; - } - rpc->e_sources[rpc->prod_idx].status = status; - rpc->e_sources[rpc->prod_idx].id = id; - rpc->prod_idx = next_prod_idx; - spin_unlock_irqrestore(&rpc->e_lock, flags); - - /* Invoke DPC handler */ - schedule_work(&rpc->dpc_handler); - - return IRQ_HANDLED; -} -EXPORT_SYMBOL_GPL(aer_irq); - -/** - * aer_alloc_rpc - allocate Root Port data structure - * @dev: pointer to the pcie_dev data structure - * - * Invoked when Root Port's AER service is loaded. - */ -static struct aer_rpc *aer_alloc_rpc(struct pcie_device *dev) -{ - struct aer_rpc *rpc; - - rpc = kzalloc(sizeof(struct aer_rpc), GFP_KERNEL); - if (!rpc) - return NULL; - - /* Initialize Root lock access, e_lock, to Root Error Status Reg */ - spin_lock_init(&rpc->e_lock); - - rpc->rpd = dev->port; - INIT_WORK(&rpc->dpc_handler, aer_isr); - mutex_init(&rpc->rpc_mutex); - - /* Use PCIe bus function to store rpc into PCIe device */ - set_service_data(dev, rpc); - - return rpc; -} - -/** - * aer_remove - clean up resources - * @dev: pointer to the pcie_dev data structure - * - * Invoked when PCI Express bus unloads or AER probe fails. - */ -static void aer_remove(struct pcie_device *dev) -{ - struct aer_rpc *rpc = get_service_data(dev); - - if (rpc) { - /* If register interrupt service, it must be free. */ - if (rpc->isr) - free_irq(dev->irq, dev); - - flush_work(&rpc->dpc_handler); - aer_disable_rootport(rpc); - kfree(rpc); - set_service_data(dev, NULL); - } -} - -/** - * aer_probe - initialize resources - * @dev: pointer to the pcie_dev data structure - * - * Invoked when PCI Express bus loads AER service driver. - */ -static int aer_probe(struct pcie_device *dev) -{ - int status; - struct aer_rpc *rpc; - struct device *device = &dev->port->dev; - - /* Alloc rpc data structure */ - rpc = aer_alloc_rpc(dev); - if (!rpc) { - dev_printk(KERN_DEBUG, device, "alloc AER rpc failed\n"); - aer_remove(dev); - return -ENOMEM; - } - - /* Request IRQ ISR */ - status = request_irq(dev->irq, aer_irq, IRQF_SHARED, "aerdrv", dev); - if (status) { - dev_printk(KERN_DEBUG, device, "request AER IRQ %d failed\n", - dev->irq); - aer_remove(dev); - return status; - } - - rpc->isr = 1; - - aer_enable_rootport(rpc); - dev_info(device, "AER enabled with IRQ %d\n", dev->irq); - return 0; -} - -/** - * aer_root_reset - reset link on Root Port - * @dev: pointer to Root Port's pci_dev data structure - * - * Invoked by Port Bus driver when performing link reset at Root Port. - */ -static pci_ers_result_t aer_root_reset(struct pci_dev *dev) -{ - u32 reg32; - int pos; - - pos = dev->aer_cap; - - /* Disable Root's interrupt in response to error messages */ - pci_read_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, ®32); - reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK; - pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32); - - pci_reset_bridge_secondary_bus(dev); - pci_printk(KERN_DEBUG, dev, "Root Port link has been reset\n"); - - /* Clear Root Error Status */ - pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, ®32); - pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, reg32); - - /* Enable Root Port's interrupt in response to error messages */ - pci_read_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, ®32); - reg32 |= ROOT_PORT_INTR_ON_MESG_MASK; - pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32); - - return PCI_ERS_RESULT_RECOVERED; -} - -/** - * aer_error_resume - clean up corresponding error status bits - * @dev: pointer to Root Port's pci_dev data structure - * - * Invoked by Port Bus driver during nonfatal recovery. - */ -static void aer_error_resume(struct pci_dev *dev) -{ - int pos; - u32 status, mask; - u16 reg16; - - /* Clean up Root device status */ - pcie_capability_read_word(dev, PCI_EXP_DEVSTA, ®16); - pcie_capability_write_word(dev, PCI_EXP_DEVSTA, reg16); - - /* Clean AER Root Error Status */ - pos = dev->aer_cap; - pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status); - pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &mask); - status &= ~mask; /* Clear corresponding nonfatal bits */ - pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status); -} - -/** - * aer_service_init - register AER root service driver - * - * Invoked when AER root service driver is loaded. - */ -static int __init aer_service_init(void) -{ - if (!pci_aer_available() || aer_acpi_firmware_first()) - return -ENXIO; - return pcie_port_service_register(&aerdriver); -} -device_initcall(aer_service_init); diff --git a/drivers/pci/pcie/aer/aerdrv.h b/drivers/pci/pcie/aer/aerdrv.h deleted file mode 100644 index 6e0ad9a68fd9..000000000000 --- a/drivers/pci/pcie/aer/aerdrv.h +++ /dev/null @@ -1,95 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2006 Intel Corp. - * Tom Long Nguyen (tom.l.nguyen@intel.com) - * Zhang Yanmin (yanmin.zhang@intel.com) - */ - -#ifndef _AERDRV_H_ -#define _AERDRV_H_ - -#include <linux/workqueue.h> -#include <linux/aer.h> -#include <linux/interrupt.h> - -#include "../portdrv.h" - -#define SYSTEM_ERROR_INTR_ON_MESG_MASK (PCI_EXP_RTCTL_SECEE| \ - PCI_EXP_RTCTL_SENFEE| \ - PCI_EXP_RTCTL_SEFEE) -#define ROOT_PORT_INTR_ON_MESG_MASK (PCI_ERR_ROOT_CMD_COR_EN| \ - PCI_ERR_ROOT_CMD_NONFATAL_EN| \ - PCI_ERR_ROOT_CMD_FATAL_EN) -#define ERR_COR_ID(d) (d & 0xffff) -#define ERR_UNCOR_ID(d) (d >> 16) - -#define AER_ERROR_SOURCES_MAX 100 - -#define AER_LOG_TLP_MASKS (PCI_ERR_UNC_POISON_TLP| \ - PCI_ERR_UNC_ECRC| \ - PCI_ERR_UNC_UNSUP| \ - PCI_ERR_UNC_COMP_ABORT| \ - PCI_ERR_UNC_UNX_COMP| \ - PCI_ERR_UNC_MALF_TLP) - -#define AER_MAX_MULTI_ERR_DEVICES 5 /* Not likely to have more */ -struct aer_err_info { - struct pci_dev *dev[AER_MAX_MULTI_ERR_DEVICES]; - int error_dev_num; - - unsigned int id:16; - - unsigned int severity:2; /* 0:NONFATAL | 1:FATAL | 2:COR */ - unsigned int __pad1:5; - unsigned int multi_error_valid:1; - - unsigned int first_error:5; - unsigned int __pad2:2; - unsigned int tlp_header_valid:1; - - unsigned int status; /* COR/UNCOR Error Status */ - unsigned int mask; /* COR/UNCOR Error Mask */ - struct aer_header_log_regs tlp; /* TLP Header */ -}; - -struct aer_err_source { - unsigned int status; - unsigned int id; -}; - -struct aer_rpc { - struct pci_dev *rpd; /* Root Port device */ - struct work_struct dpc_handler; - struct aer_err_source e_sources[AER_ERROR_SOURCES_MAX]; - struct aer_err_info e_info; - unsigned short prod_idx; /* Error Producer Index */ - unsigned short cons_idx; /* Error Consumer Index */ - int isr; - spinlock_t e_lock; /* - * Lock access to Error Status/ID Regs - * and error producer/consumer index - */ - struct mutex rpc_mutex; /* - * only one thread could do - * recovery on the same - * root port hierarchy - */ -}; - -extern struct bus_type pcie_port_bus_type; -void aer_isr(struct work_struct *work); -void aer_print_error(struct pci_dev *dev, struct aer_err_info *info); -void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info); -irqreturn_t aer_irq(int irq, void *context); - -#ifdef CONFIG_ACPI_APEI -int pcie_aer_get_firmware_first(struct pci_dev *pci_dev); -#else -static inline int pcie_aer_get_firmware_first(struct pci_dev *pci_dev) -{ - if (pci_dev->__aer_firmware_first_valid) - return pci_dev->__aer_firmware_first; - return 0; -} -#endif -#endif /* _AERDRV_H_ */ diff --git a/drivers/pci/pcie/aer/aerdrv_acpi.c b/drivers/pci/pcie/aer/aerdrv_acpi.c deleted file mode 100644 index 08c87de13cb8..000000000000 --- a/drivers/pci/pcie/aer/aerdrv_acpi.c +++ /dev/null @@ -1,141 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Access ACPI _OSC method - * - * Copyright (C) 2006 Intel Corp. - * Tom Long Nguyen (tom.l.nguyen@intel.com) - * Zhang Yanmin (yanmin.zhang@intel.com) - */ - -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/pm.h> -#include <linux/suspend.h> -#include <linux/acpi.h> -#include <linux/pci-acpi.h> -#include <linux/delay.h> -#include <acpi/apei.h> -#include "aerdrv.h" - -#ifdef CONFIG_ACPI_APEI -static inline int hest_match_pci(struct acpi_hest_aer_common *p, - struct pci_dev *pci) -{ - return ACPI_HEST_SEGMENT(p->bus) == pci_domain_nr(pci->bus) && - ACPI_HEST_BUS(p->bus) == pci->bus->number && - p->device == PCI_SLOT(pci->devfn) && - p->function == PCI_FUNC(pci->devfn); -} - -static inline bool hest_match_type(struct acpi_hest_header *hest_hdr, - struct pci_dev *dev) -{ - u16 hest_type = hest_hdr->type; - u8 pcie_type = pci_pcie_type(dev); - - if ((hest_type == ACPI_HEST_TYPE_AER_ROOT_PORT && - pcie_type == PCI_EXP_TYPE_ROOT_PORT) || - (hest_type == ACPI_HEST_TYPE_AER_ENDPOINT && - pcie_type == PCI_EXP_TYPE_ENDPOINT) || - (hest_type == ACPI_HEST_TYPE_AER_BRIDGE && - (dev->class >> 16) == PCI_BASE_CLASS_BRIDGE)) - return true; - return false; -} - -struct aer_hest_parse_info { - struct pci_dev *pci_dev; - int firmware_first; -}; - -static int hest_source_is_pcie_aer(struct acpi_hest_header *hest_hdr) -{ - if (hest_hdr->type == ACPI_HEST_TYPE_AER_ROOT_PORT || - hest_hdr->type == ACPI_HEST_TYPE_AER_ENDPOINT || - hest_hdr->type == ACPI_HEST_TYPE_AER_BRIDGE) - return 1; - return 0; -} - -static int aer_hest_parse(struct acpi_hest_header *hest_hdr, void *data) -{ - struct aer_hest_parse_info *info = data; - struct acpi_hest_aer_common *p; - int ff; - - if (!hest_source_is_pcie_aer(hest_hdr)) - return 0; - - p = (struct acpi_hest_aer_common *)(hest_hdr + 1); - ff = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST); - - /* - * If no specific device is supplied, determine whether - * FIRMWARE_FIRST is set for *any* PCIe device. - */ - if (!info->pci_dev) { - info->firmware_first |= ff; - return 0; - } - - /* Otherwise, check the specific device */ - if (p->flags & ACPI_HEST_GLOBAL) { - if (hest_match_type(hest_hdr, info->pci_dev)) - info->firmware_first = ff; - } else - if (hest_match_pci(p, info->pci_dev)) - info->firmware_first = ff; - - return 0; -} - -static void aer_set_firmware_first(struct pci_dev *pci_dev) -{ - int rc; - struct aer_hest_parse_info info = { - .pci_dev = pci_dev, - .firmware_first = 0, - }; - - rc = apei_hest_parse(aer_hest_parse, &info); - - if (rc) - pci_dev->__aer_firmware_first = 0; - else - pci_dev->__aer_firmware_first = info.firmware_first; - pci_dev->__aer_firmware_first_valid = 1; -} - -int pcie_aer_get_firmware_first(struct pci_dev *dev) -{ - if (!pci_is_pcie(dev)) - return 0; - - if (!dev->__aer_firmware_first_valid) - aer_set_firmware_first(dev); - return dev->__aer_firmware_first; -} - -static bool aer_firmware_first; - -/** - * aer_acpi_firmware_first - Check if APEI should control AER. - */ -bool aer_acpi_firmware_first(void) -{ - static bool parsed = false; - struct aer_hest_parse_info info = { - .pci_dev = NULL, /* Check all PCIe devices */ - .firmware_first = 0, - }; - - if (!parsed) { - apei_hest_parse(aer_hest_parse, &info); - aer_firmware_first = info.firmware_first; - parsed = true; - } - return aer_firmware_first; -} -#endif diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c deleted file mode 100644 index 42d4f3f32282..000000000000 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ /dev/null @@ -1,496 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Implement the core part of PCIe AER. When a PCIe error is delivered, an - * error message will be collected and printed to console, then an error - * recovery procedure will be executed by following the PCI error recovery - * rules. - * - * Copyright (C) 2006 Intel Corp. - * Tom Long Nguyen (tom.l.nguyen@intel.com) - * Zhang Yanmin (yanmin.zhang@intel.com) - */ - -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/pm.h> -#include <linux/suspend.h> -#include <linux/delay.h> -#include <linux/slab.h> -#include <linux/kfifo.h> -#include "aerdrv.h" -#include "../../pci.h" - -#define PCI_EXP_AER_FLAGS (PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | \ - PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE) - -int pci_enable_pcie_error_reporting(struct pci_dev *dev) -{ - if (pcie_aer_get_firmware_first(dev)) - return -EIO; - - if (!dev->aer_cap) - return -EIO; - - return pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_AER_FLAGS); -} -EXPORT_SYMBOL_GPL(pci_enable_pcie_error_reporting); - -int pci_disable_pcie_error_reporting(struct pci_dev *dev) -{ - if (pcie_aer_get_firmware_first(dev)) - return -EIO; - - return pcie_capability_clear_word(dev, PCI_EXP_DEVCTL, - PCI_EXP_AER_FLAGS); -} -EXPORT_SYMBOL_GPL(pci_disable_pcie_error_reporting); - -int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev) -{ - int pos; - u32 status; - - pos = dev->aer_cap; - if (!pos) - return -EIO; - - pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status); - if (status) - pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status); - - return 0; -} -EXPORT_SYMBOL_GPL(pci_cleanup_aer_uncorrect_error_status); - -int pci_cleanup_aer_error_status_regs(struct pci_dev *dev) -{ - int pos; - u32 status; - int port_type; - - if (!pci_is_pcie(dev)) - return -ENODEV; - - pos = dev->aer_cap; - if (!pos) - return -EIO; - - port_type = pci_pcie_type(dev); - if (port_type == PCI_EXP_TYPE_ROOT_PORT) { - pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &status); - pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, status); - } - - pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, &status); - pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS, status); - - pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status); - pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status); - - return 0; -} - -int pci_aer_init(struct pci_dev *dev) -{ - dev->aer_cap = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); - return pci_cleanup_aer_error_status_regs(dev); -} - -/** - * add_error_device - list device to be handled - * @e_info: pointer to error info - * @dev: pointer to pci_dev to be added - */ -static int add_error_device(struct aer_err_info *e_info, struct pci_dev *dev) -{ - if (e_info->error_dev_num < AER_MAX_MULTI_ERR_DEVICES) { - e_info->dev[e_info->error_dev_num] = dev; - e_info->error_dev_num++; - return 0; - } - return -ENOSPC; -} - -/** - * is_error_source - check whether the device is source of reported error - * @dev: pointer to pci_dev to be checked - * @e_info: pointer to reported error info - */ -static bool is_error_source(struct pci_dev *dev, struct aer_err_info *e_info) -{ - int pos; - u32 status, mask; - u16 reg16; - - /* - * When bus id is equal to 0, it might be a bad id - * reported by root port. - */ - if ((PCI_BUS_NUM(e_info->id) != 0) && - !(dev->bus->bus_flags & PCI_BUS_FLAGS_NO_AERSID)) { - /* Device ID match? */ - if (e_info->id == ((dev->bus->number << 8) | dev->devfn)) - return true; - - /* Continue id comparing if there is no multiple error */ - if (!e_info->multi_error_valid) - return false; - } - - /* - * When either - * 1) bus id is equal to 0. Some ports might lose the bus - * id of error source id; - * 2) bus flag PCI_BUS_FLAGS_NO_AERSID is set - * 3) There are multiple errors and prior ID comparing fails; - * We check AER status registers to find possible reporter. - */ - if (atomic_read(&dev->enable_cnt) == 0) - return false; - - /* Check if AER is enabled */ - pcie_capability_read_word(dev, PCI_EXP_DEVCTL, ®16); - if (!(reg16 & PCI_EXP_AER_FLAGS)) - return false; - - pos = dev->aer_cap; - if (!pos) - return false; - - /* Check if error is recorded */ - if (e_info->severity == AER_CORRECTABLE) { - pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, &status); - pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, &mask); - } else { - pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status); - pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, &mask); - } - if (status & ~mask) - return true; - - return false; -} - -static int find_device_iter(struct pci_dev *dev, void *data) -{ - struct aer_err_info *e_info = (struct aer_err_info *)data; - - if (is_error_source(dev, e_info)) { - /* List this device */ - if (add_error_device(e_info, dev)) { - /* We cannot handle more... Stop iteration */ - /* TODO: Should print error message here? */ - return 1; - } - - /* If there is only a single error, stop iteration */ - if (!e_info->multi_error_valid) - return 1; - } - return 0; -} - -/** - * find_source_device - search through device hierarchy for source device - * @parent: pointer to Root Port pci_dev data structure - * @e_info: including detailed error information such like id - * - * Return true if found. - * - * Invoked by DPC when error is detected at the Root Port. - * Caller of this function must set id, severity, and multi_error_valid of - * struct aer_err_info pointed by @e_info properly. This function must fill - * e_info->error_dev_num and e_info->dev[], based on the given information. - */ -static bool find_source_device(struct pci_dev *parent, - struct aer_err_info *e_info) -{ - struct pci_dev *dev = parent; - int result; - - /* Must reset in this function */ - e_info->error_dev_num = 0; - - /* Is Root Port an agent that sends error message? */ - result = find_device_iter(dev, e_info); - if (result) - return true; - - pci_walk_bus(parent->subordinate, find_device_iter, e_info); - - if (!e_info->error_dev_num) { - pci_printk(KERN_DEBUG, parent, "can't find device of ID%04x\n", - e_info->id); - return false; - } - return true; -} - -/** - * handle_error_source - handle logging error into an event log - * @dev: pointer to pci_dev data structure of error source device - * @info: comprehensive error information - * - * Invoked when an error being detected by Root Port. - */ -static void handle_error_source(struct pci_dev *dev, struct aer_err_info *info) -{ - int pos; - - if (info->severity == AER_CORRECTABLE) { - /* - * Correctable error does not need software intervention. - * No need to go through error recovery process. - */ - pos = dev->aer_cap; - if (pos) - pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS, - info->status); - } else if (info->severity == AER_NONFATAL) - pcie_do_nonfatal_recovery(dev); - else if (info->severity == AER_FATAL) - pcie_do_fatal_recovery(dev, PCIE_PORT_SERVICE_AER); -} - -#ifdef CONFIG_ACPI_APEI_PCIEAER - -#define AER_RECOVER_RING_ORDER 4 -#define AER_RECOVER_RING_SIZE (1 << AER_RECOVER_RING_ORDER) - -struct aer_recover_entry { - u8 bus; - u8 devfn; - u16 domain; - int severity; - struct aer_capability_regs *regs; -}; - -static DEFINE_KFIFO(aer_recover_ring, struct aer_recover_entry, - AER_RECOVER_RING_SIZE); - -static void aer_recover_work_func(struct work_struct *work) -{ - struct aer_recover_entry entry; - struct pci_dev *pdev; - - while (kfifo_get(&aer_recover_ring, &entry)) { - pdev = pci_get_domain_bus_and_slot(entry.domain, entry.bus, - entry.devfn); - if (!pdev) { - pr_err("AER recover: Can not find pci_dev for %04x:%02x:%02x:%x\n", - entry.domain, entry.bus, - PCI_SLOT(entry.devfn), PCI_FUNC(entry.devfn)); - continue; - } - cper_print_aer(pdev, entry.severity, entry.regs); - if (entry.severity == AER_NONFATAL) - pcie_do_nonfatal_recovery(pdev); - else if (entry.severity == AER_FATAL) - pcie_do_fatal_recovery(pdev, PCIE_PORT_SERVICE_AER); - pci_dev_put(pdev); - } -} - -/* - * Mutual exclusion for writers of aer_recover_ring, reader side don't - * need lock, because there is only one reader and lock is not needed - * between reader and writer. - */ -static DEFINE_SPINLOCK(aer_recover_ring_lock); -static DECLARE_WORK(aer_recover_work, aer_recover_work_func); - -void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn, - int severity, struct aer_capability_regs *aer_regs) -{ - unsigned long flags; - struct aer_recover_entry entry = { - .bus = bus, - .devfn = devfn, - .domain = domain, - .severity = severity, - .regs = aer_regs, - }; - - spin_lock_irqsave(&aer_recover_ring_lock, flags); - if (kfifo_put(&aer_recover_ring, entry)) - schedule_work(&aer_recover_work); - else - pr_err("AER recover: Buffer overflow when recovering AER for %04x:%02x:%02x:%x\n", - domain, bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); - spin_unlock_irqrestore(&aer_recover_ring_lock, flags); -} -EXPORT_SYMBOL_GPL(aer_recover_queue); -#endif - -/** - * get_device_error_info - read error status from dev and store it to info - * @dev: pointer to the device expected to have a error record - * @info: pointer to structure to store the error record - * - * Return 1 on success, 0 on error. - * - * Note that @info is reused among all error devices. Clear fields properly. - */ -static int get_device_error_info(struct pci_dev *dev, struct aer_err_info *info) -{ - int pos, temp; - - /* Must reset in this function */ - info->status = 0; - info->tlp_header_valid = 0; - - pos = dev->aer_cap; - - /* The device might not support AER */ - if (!pos) - return 0; - - if (info->severity == AER_CORRECTABLE) { - pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, - &info->status); - pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, - &info->mask); - if (!(info->status & ~info->mask)) - return 0; - } else if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || - info->severity == AER_NONFATAL) { - - /* Link is still healthy for IO reads */ - pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, - &info->status); - pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, - &info->mask); - if (!(info->status & ~info->mask)) - return 0; - - /* Get First Error Pointer */ - pci_read_config_dword(dev, pos + PCI_ERR_CAP, &temp); - info->first_error = PCI_ERR_CAP_FEP(temp); - - if (info->status & AER_LOG_TLP_MASKS) { - info->tlp_header_valid = 1; - pci_read_config_dword(dev, - pos + PCI_ERR_HEADER_LOG, &info->tlp.dw0); - pci_read_config_dword(dev, - pos + PCI_ERR_HEADER_LOG + 4, &info->tlp.dw1); - pci_read_config_dword(dev, - pos + PCI_ERR_HEADER_LOG + 8, &info->tlp.dw2); - pci_read_config_dword(dev, - pos + PCI_ERR_HEADER_LOG + 12, &info->tlp.dw3); - } - } - - return 1; -} - -static inline void aer_process_err_devices(struct aer_err_info *e_info) -{ - int i; - - /* Report all before handle them, not to lost records by reset etc. */ - for (i = 0; i < e_info->error_dev_num && e_info->dev[i]; i++) { - if (get_device_error_info(e_info->dev[i], e_info)) - aer_print_error(e_info->dev[i], e_info); - } - for (i = 0; i < e_info->error_dev_num && e_info->dev[i]; i++) { - if (get_device_error_info(e_info->dev[i], e_info)) - handle_error_source(e_info->dev[i], e_info); - } -} - -/** - * aer_isr_one_error - consume an error detected by root port - * @rpc: pointer to the root port which holds an error - * @e_src: pointer to an error source - */ -static void aer_isr_one_error(struct aer_rpc *rpc, - struct aer_err_source *e_src) -{ - struct pci_dev *pdev = rpc->rpd; - struct aer_err_info *e_info = &rpc->e_info; - - /* - * There is a possibility that both correctable error and - * uncorrectable error being logged. Report correctable error first. - */ - if (e_src->status & PCI_ERR_ROOT_COR_RCV) { - e_info->id = ERR_COR_ID(e_src->id); - e_info->severity = AER_CORRECTABLE; - - if (e_src->status & PCI_ERR_ROOT_MULTI_COR_RCV) - e_info->multi_error_valid = 1; - else - e_info->multi_error_valid = 0; - aer_print_port_info(pdev, e_info); - - if (find_source_device(pdev, e_info)) - aer_process_err_devices(e_info); - } - - if (e_src->status & PCI_ERR_ROOT_UNCOR_RCV) { - e_info->id = ERR_UNCOR_ID(e_src->id); - - if (e_src->status & PCI_ERR_ROOT_FATAL_RCV) - e_info->severity = AER_FATAL; - else - e_info->severity = AER_NONFATAL; - - if (e_src->status & PCI_ERR_ROOT_MULTI_UNCOR_RCV) - e_info->multi_error_valid = 1; - else - e_info->multi_error_valid = 0; - - aer_print_port_info(pdev, e_info); - - if (find_source_device(pdev, e_info)) - aer_process_err_devices(e_info); - } -} - -/** - * get_e_source - retrieve an error source - * @rpc: pointer to the root port which holds an error - * @e_src: pointer to store retrieved error source - * - * Return 1 if an error source is retrieved, otherwise 0. - * - * Invoked by DPC handler to consume an error. - */ -static int get_e_source(struct aer_rpc *rpc, struct aer_err_source *e_src) -{ - unsigned long flags; - - /* Lock access to Root error producer/consumer index */ - spin_lock_irqsave(&rpc->e_lock, flags); - if (rpc->prod_idx == rpc->cons_idx) { - spin_unlock_irqrestore(&rpc->e_lock, flags); - return 0; - } - - *e_src = rpc->e_sources[rpc->cons_idx]; - rpc->cons_idx++; - if (rpc->cons_idx == AER_ERROR_SOURCES_MAX) - rpc->cons_idx = 0; - spin_unlock_irqrestore(&rpc->e_lock, flags); - - return 1; -} - -/** - * aer_isr - consume errors detected by root port - * @work: definition of this work item - * - * Invoked, as DPC, when root port records new detected error - */ -void aer_isr(struct work_struct *work) -{ - struct aer_rpc *rpc = container_of(work, struct aer_rpc, dpc_handler); - struct aer_err_source uninitialized_var(e_src); - - mutex_lock(&rpc->rpc_mutex); - while (get_e_source(rpc, &e_src)) - aer_isr_one_error(rpc, &e_src); - mutex_unlock(&rpc->rpc_mutex); -} diff --git a/drivers/pci/pcie/aer/aerdrv_errprint.c b/drivers/pci/pcie/aer/aerdrv_errprint.c deleted file mode 100644 index 4985bdf64c2e..000000000000 --- a/drivers/pci/pcie/aer/aerdrv_errprint.c +++ /dev/null @@ -1,260 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Format error messages and print them to console. - * - * Copyright (C) 2006 Intel Corp. - * Tom Long Nguyen (tom.l.nguyen@intel.com) - * Zhang Yanmin (yanmin.zhang@intel.com) - */ - -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/pm.h> -#include <linux/suspend.h> -#include <linux/cper.h> - -#include "aerdrv.h" -#include <ras/ras_event.h> - -#define AER_AGENT_RECEIVER 0 -#define AER_AGENT_REQUESTER 1 -#define AER_AGENT_COMPLETER 2 -#define AER_AGENT_TRANSMITTER 3 - -#define AER_AGENT_REQUESTER_MASK(t) ((t == AER_CORRECTABLE) ? \ - 0 : (PCI_ERR_UNC_COMP_TIME|PCI_ERR_UNC_UNSUP)) -#define AER_AGENT_COMPLETER_MASK(t) ((t == AER_CORRECTABLE) ? \ - 0 : PCI_ERR_UNC_COMP_ABORT) -#define AER_AGENT_TRANSMITTER_MASK(t) ((t == AER_CORRECTABLE) ? \ - (PCI_ERR_COR_REP_ROLL|PCI_ERR_COR_REP_TIMER) : 0) - -#define AER_GET_AGENT(t, e) \ - ((e & AER_AGENT_COMPLETER_MASK(t)) ? AER_AGENT_COMPLETER : \ - (e & AER_AGENT_REQUESTER_MASK(t)) ? AER_AGENT_REQUESTER : \ - (e & AER_AGENT_TRANSMITTER_MASK(t)) ? AER_AGENT_TRANSMITTER : \ - AER_AGENT_RECEIVER) - -#define AER_PHYSICAL_LAYER_ERROR 0 -#define AER_DATA_LINK_LAYER_ERROR 1 -#define AER_TRANSACTION_LAYER_ERROR 2 - -#define AER_PHYSICAL_LAYER_ERROR_MASK(t) ((t == AER_CORRECTABLE) ? \ - PCI_ERR_COR_RCVR : 0) -#define AER_DATA_LINK_LAYER_ERROR_MASK(t) ((t == AER_CORRECTABLE) ? \ - (PCI_ERR_COR_BAD_TLP| \ - PCI_ERR_COR_BAD_DLLP| \ - PCI_ERR_COR_REP_ROLL| \ - PCI_ERR_COR_REP_TIMER) : PCI_ERR_UNC_DLP) - -#define AER_GET_LAYER_ERROR(t, e) \ - ((e & AER_PHYSICAL_LAYER_ERROR_MASK(t)) ? AER_PHYSICAL_LAYER_ERROR : \ - (e & AER_DATA_LINK_LAYER_ERROR_MASK(t)) ? AER_DATA_LINK_LAYER_ERROR : \ - AER_TRANSACTION_LAYER_ERROR) - -/* - * AER error strings - */ -static const char *aer_error_severity_string[] = { - "Uncorrected (Non-Fatal)", - "Uncorrected (Fatal)", - "Corrected" -}; - -static const char *aer_error_layer[] = { - "Physical Layer", - "Data Link Layer", - "Transaction Layer" -}; - -static const char *aer_correctable_error_string[] = { - "Receiver Error", /* Bit Position 0 */ - NULL, - NULL, - NULL, - NULL, - NULL, - "Bad TLP", /* Bit Position 6 */ - "Bad DLLP", /* Bit Position 7 */ - "RELAY_NUM Rollover", /* Bit Position 8 */ - NULL, - NULL, - NULL, - "Replay Timer Timeout", /* Bit Position 12 */ - "Advisory Non-Fatal", /* Bit Position 13 */ - "Corrected Internal Error", /* Bit Position 14 */ - "Header Log Overflow", /* Bit Position 15 */ -}; - -static const char *aer_uncorrectable_error_string[] = { - "Undefined", /* Bit Position 0 */ - NULL, - NULL, - NULL, - "Data Link Protocol", /* Bit Position 4 */ - "Surprise Down Error", /* Bit Position 5 */ - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "Poisoned TLP", /* Bit Position 12 */ - "Flow Control Protocol", /* Bit Position 13 */ - "Completion Timeout", /* Bit Position 14 */ - "Completer Abort", /* Bit Position 15 */ - "Unexpected Completion", /* Bit Position 16 */ - "Receiver Overflow", /* Bit Position 17 */ - "Malformed TLP", /* Bit Position 18 */ - "ECRC", /* Bit Position 19 */ - "Unsupported Request", /* Bit Position 20 */ - "ACS Violation", /* Bit Position 21 */ - "Uncorrectable Internal Error", /* Bit Position 22 */ - "MC Blocked TLP", /* Bit Position 23 */ - "AtomicOp Egress Blocked", /* Bit Position 24 */ - "TLP Prefix Blocked Error", /* Bit Position 25 */ -}; - -static const char *aer_agent_string[] = { - "Receiver ID", - "Requester ID", - "Completer ID", - "Transmitter ID" -}; - -static void __print_tlp_header(struct pci_dev *dev, - struct aer_header_log_regs *t) -{ - pci_err(dev, " TLP Header: %08x %08x %08x %08x\n", - t->dw0, t->dw1, t->dw2, t->dw3); -} - -static void __aer_print_error(struct pci_dev *dev, - struct aer_err_info *info) -{ - int i, status; - const char *errmsg = NULL; - status = (info->status & ~info->mask); - - for (i = 0; i < 32; i++) { - if (!(status & (1 << i))) - continue; - - if (info->severity == AER_CORRECTABLE) - errmsg = i < ARRAY_SIZE(aer_correctable_error_string) ? - aer_correctable_error_string[i] : NULL; - else - errmsg = i < ARRAY_SIZE(aer_uncorrectable_error_string) ? - aer_uncorrectable_error_string[i] : NULL; - - if (errmsg) - pci_err(dev, " [%2d] %-22s%s\n", i, errmsg, - info->first_error == i ? " (First)" : ""); - else - pci_err(dev, " [%2d] Unknown Error Bit%s\n", - i, info->first_error == i ? " (First)" : ""); - } -} - -void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) -{ - int layer, agent; - int id = ((dev->bus->number << 8) | dev->devfn); - - if (!info->status) { - pci_err(dev, "PCIe Bus Error: severity=%s, type=Inaccessible, (Unregistered Agent ID)\n", - aer_error_severity_string[info->severity]); - goto out; - } - - layer = AER_GET_LAYER_ERROR(info->severity, info->status); - agent = AER_GET_AGENT(info->severity, info->status); - - pci_err(dev, "PCIe Bus Error: severity=%s, type=%s, (%s)\n", - aer_error_severity_string[info->severity], - aer_error_layer[layer], aer_agent_string[agent]); - - pci_err(dev, " device [%04x:%04x] error status/mask=%08x/%08x\n", - dev->vendor, dev->device, - info->status, info->mask); - - __aer_print_error(dev, info); - - if (info->tlp_header_valid) - __print_tlp_header(dev, &info->tlp); - -out: - if (info->id && info->error_dev_num > 1 && info->id == id) - pci_err(dev, " Error of this Agent is reported first\n"); - - trace_aer_event(dev_name(&dev->dev), (info->status & ~info->mask), - info->severity, info->tlp_header_valid, &info->tlp); -} - -void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info) -{ - u8 bus = info->id >> 8; - u8 devfn = info->id & 0xff; - - pci_info(dev, "AER: %s%s error received: %04x:%02x:%02x.%d\n", - info->multi_error_valid ? "Multiple " : "", - aer_error_severity_string[info->severity], - pci_domain_nr(dev->bus), bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); -} - -#ifdef CONFIG_ACPI_APEI_PCIEAER -int cper_severity_to_aer(int cper_severity) -{ - switch (cper_severity) { - case CPER_SEV_RECOVERABLE: - return AER_NONFATAL; - case CPER_SEV_FATAL: - return AER_FATAL; - default: - return AER_CORRECTABLE; - } -} -EXPORT_SYMBOL_GPL(cper_severity_to_aer); - -void cper_print_aer(struct pci_dev *dev, int aer_severity, - struct aer_capability_regs *aer) -{ - int layer, agent, tlp_header_valid = 0; - u32 status, mask; - struct aer_err_info info; - - if (aer_severity == AER_CORRECTABLE) { - status = aer->cor_status; - mask = aer->cor_mask; - } else { - status = aer->uncor_status; - mask = aer->uncor_mask; - tlp_header_valid = status & AER_LOG_TLP_MASKS; - } - - layer = AER_GET_LAYER_ERROR(aer_severity, status); - agent = AER_GET_AGENT(aer_severity, status); - - memset(&info, 0, sizeof(info)); - info.severity = aer_severity; - info.status = status; - info.mask = mask; - info.first_error = PCI_ERR_CAP_FEP(aer->cap_control); - - pci_err(dev, "aer_status: 0x%08x, aer_mask: 0x%08x\n", status, mask); - __aer_print_error(dev, &info); - pci_err(dev, "aer_layer=%s, aer_agent=%s\n", - aer_error_layer[layer], aer_agent_string[agent]); - - if (aer_severity != AER_CORRECTABLE) - pci_err(dev, "aer_uncor_severity: 0x%08x\n", - aer->uncor_severity); - - if (tlp_header_valid) - __print_tlp_header(dev, &aer->header_log); - - trace_aer_event(dev_name(&dev->dev), (status & ~mask), - aer_severity, tlp_header_valid, &aer->header_log); -} -#endif diff --git a/drivers/pci/pcie/aer/ecrc.c b/drivers/pci/pcie/aer/ecrc.c deleted file mode 100644 index 039efb606e31..000000000000 --- a/drivers/pci/pcie/aer/ecrc.c +++ /dev/null @@ -1,117 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Enable/disable PCIe ECRC checking - * - * (C) Copyright 2009 Hewlett-Packard Development Company, L.P. - * Andrew Patterson <andrew.patterson@hp.com> - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/pci.h> -#include <linux/pci_regs.h> -#include <linux/errno.h> -#include "../../pci.h" - -#define ECRC_POLICY_DEFAULT 0 /* ECRC set by BIOS */ -#define ECRC_POLICY_OFF 1 /* ECRC off for performance */ -#define ECRC_POLICY_ON 2 /* ECRC on for data integrity */ - -static int ecrc_policy = ECRC_POLICY_DEFAULT; - -static const char *ecrc_policy_str[] = { - [ECRC_POLICY_DEFAULT] = "bios", - [ECRC_POLICY_OFF] = "off", - [ECRC_POLICY_ON] = "on" -}; - -/** - * enable_ercr_checking - enable PCIe ECRC checking for a device - * @dev: the PCI device - * - * Returns 0 on success, or negative on failure. - */ -static int enable_ecrc_checking(struct pci_dev *dev) -{ - int pos; - u32 reg32; - - if (!pci_is_pcie(dev)) - return -ENODEV; - - pos = dev->aer_cap; - if (!pos) - return -ENODEV; - - pci_read_config_dword(dev, pos + PCI_ERR_CAP, ®32); - if (reg32 & PCI_ERR_CAP_ECRC_GENC) - reg32 |= PCI_ERR_CAP_ECRC_GENE; - if (reg32 & PCI_ERR_CAP_ECRC_CHKC) - reg32 |= PCI_ERR_CAP_ECRC_CHKE; - pci_write_config_dword(dev, pos + PCI_ERR_CAP, reg32); - - return 0; -} - -/** - * disable_ercr_checking - disables PCIe ECRC checking for a device - * @dev: the PCI device - * - * Returns 0 on success, or negative on failure. - */ -static int disable_ecrc_checking(struct pci_dev *dev) -{ - int pos; - u32 reg32; - - if (!pci_is_pcie(dev)) - return -ENODEV; - - pos = dev->aer_cap; - if (!pos) - return -ENODEV; - - pci_read_config_dword(dev, pos + PCI_ERR_CAP, ®32); - reg32 &= ~(PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE); - pci_write_config_dword(dev, pos + PCI_ERR_CAP, reg32); - - return 0; -} - -/** - * pcie_set_ecrc_checking - set/unset PCIe ECRC checking for a device based on global policy - * @dev: the PCI device - */ -void pcie_set_ecrc_checking(struct pci_dev *dev) -{ - switch (ecrc_policy) { - case ECRC_POLICY_DEFAULT: - return; - case ECRC_POLICY_OFF: - disable_ecrc_checking(dev); - break; - case ECRC_POLICY_ON: - enable_ecrc_checking(dev); - break; - default: - return; - } -} - -/** - * pcie_ecrc_get_policy - parse kernel command-line ecrc option - */ -void pcie_ecrc_get_policy(char *str) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(ecrc_policy_str); i++) - if (!strncmp(str, ecrc_policy_str[i], - strlen(ecrc_policy_str[i]))) - break; - if (i >= ARRAY_SIZE(ecrc_policy_str)) - return; - - ecrc_policy = i; -} diff --git a/drivers/pci/pcie/aer/aer_inject.c b/drivers/pci/pcie/aer_inject.c index a49090935303..0eb24346cad3 100644 --- a/drivers/pci/pcie/aer/aer_inject.c +++ b/drivers/pci/pcie/aer_inject.c @@ -21,7 +21,8 @@ #include <linux/uaccess.h> #include <linux/stddef.h> #include <linux/device.h> -#include "aerdrv.h" + +#include "portdrv.h" /* Override the existing corrected and uncorrected error masks */ static bool aer_mask_override; diff --git a/drivers/pci/pcie/dpc.c b/drivers/pci/pcie/dpc.c index d6436681c535..921ed979109d 100644 --- a/drivers/pci/pcie/dpc.c +++ b/drivers/pci/pcie/dpc.c @@ -13,7 +13,6 @@ #include "portdrv.h" #include "../pci.h" -#include "aer/aerdrv.h" struct dpc_dev { struct pcie_device *dev; diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h index 2bb5db7b53e6..6ffc797a0dc1 100644 --- a/drivers/pci/pcie/portdrv.h +++ b/drivers/pci/pcie/portdrv.h @@ -110,6 +110,21 @@ static inline bool pcie_pme_no_msi(void) { return false; } static inline void pcie_pme_interrupt_enable(struct pci_dev *dev, bool en) {} #endif /* !CONFIG_PCIE_PME */ +#ifdef CONFIG_ACPI_APEI +int pcie_aer_get_firmware_first(struct pci_dev *pci_dev); +#else +static inline int pcie_aer_get_firmware_first(struct pci_dev *pci_dev) +{ + if (pci_dev->__aer_firmware_first_valid) + return pci_dev->__aer_firmware_first; + return 0; +} +#endif + +#ifdef CONFIG_PCIEAER +irqreturn_t aer_irq(int irq, void *context); +#endif + struct pcie_port_service_driver *pcie_port_find_service(struct pci_dev *dev, u32 service); struct device *pcie_port_find_device(struct pci_dev *dev, u32 service); diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index 102646fedb56..ac0672b8dfca 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c @@ -1481,11 +1481,11 @@ static ssize_t pccard_extract_cis(struct pcmcia_socket *s, char *buf, u_char *tuplebuffer; u_char *tempbuffer; - tuplebuffer = kmalloc(sizeof(u_char) * 256, GFP_KERNEL); + tuplebuffer = kmalloc_array(256, sizeof(u_char), GFP_KERNEL); if (!tuplebuffer) return -ENOMEM; - tempbuffer = kmalloc(sizeof(u_char) * 258, GFP_KERNEL); + tempbuffer = kmalloc_array(258, sizeof(u_char), GFP_KERNEL); if (!tempbuffer) { ret = -ENOMEM; goto free_tuple; diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c index 959ae3e65ef8..f0af9985ca09 100644 --- a/drivers/pcmcia/pd6729.c +++ b/drivers/pcmcia/pd6729.c @@ -628,7 +628,7 @@ static int pd6729_pci_probe(struct pci_dev *dev, char configbyte; struct pd6729_socket *socket; - socket = kzalloc(sizeof(struct pd6729_socket) * MAX_SOCKETS, + socket = kcalloc(MAX_SOCKETS, sizeof(struct pd6729_socket), GFP_KERNEL); if (!socket) { dev_warn(&dev->dev, "failed to kzalloc socket.\n"); diff --git a/drivers/pinctrl/bcm/pinctrl-bcm2835.c b/drivers/pinctrl/bcm/pinctrl-bcm2835.c index 136ccaf53df8..fa530913a2c8 100644 --- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c +++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c @@ -771,8 +771,8 @@ static int bcm2835_pctl_dt_node_to_map(struct pinctrl_dev *pctldev, maps_per_pin++; if (num_pulls) maps_per_pin++; - cur_map = maps = kzalloc(num_pins * maps_per_pin * sizeof(*maps), - GFP_KERNEL); + cur_map = maps = kcalloc(num_pins * maps_per_pin, sizeof(*maps), + GFP_KERNEL); if (!maps) return -ENOMEM; diff --git a/drivers/pinctrl/berlin/berlin.c b/drivers/pinctrl/berlin/berlin.c index a620a8e8fa78..d6d183e9db17 100644 --- a/drivers/pinctrl/berlin/berlin.c +++ b/drivers/pinctrl/berlin/berlin.c @@ -216,8 +216,9 @@ static int berlin_pinctrl_build_state(struct platform_device *pdev) } /* we will reallocate later */ - pctrl->functions = devm_kzalloc(&pdev->dev, - max_functions * sizeof(*pctrl->functions), + pctrl->functions = devm_kcalloc(&pdev->dev, + max_functions, + sizeof(*pctrl->functions), GFP_KERNEL); if (!pctrl->functions) return -ENOMEM; @@ -261,8 +262,9 @@ static int berlin_pinctrl_build_state(struct platform_device *pdev) if (!function->groups) { function->groups = - devm_kzalloc(&pdev->dev, - function->ngroups * sizeof(char *), + devm_kcalloc(&pdev->dev, + function->ngroups, + sizeof(char *), GFP_KERNEL); if (!function->groups) diff --git a/drivers/pinctrl/freescale/pinctrl-imx.c b/drivers/pinctrl/freescale/pinctrl-imx.c index e582a21cfe54..1c6bb15579e1 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx.c +++ b/drivers/pinctrl/freescale/pinctrl-imx.c @@ -81,7 +81,8 @@ static int imx_dt_node_to_map(struct pinctrl_dev *pctldev, map_num++; } - new_map = kmalloc(sizeof(struct pinctrl_map) * map_num, GFP_KERNEL); + new_map = kmalloc_array(map_num, sizeof(struct pinctrl_map), + GFP_KERNEL); if (!new_map) return -ENOMEM; @@ -476,10 +477,12 @@ static int imx_pinctrl_parse_groups(struct device_node *np, config = imx_pinconf_parse_generic_config(np, ipctl); grp->num_pins = size / pin_size; - grp->data = devm_kzalloc(ipctl->dev, grp->num_pins * - sizeof(struct imx_pin), GFP_KERNEL); - grp->pins = devm_kzalloc(ipctl->dev, grp->num_pins * - sizeof(unsigned int), GFP_KERNEL); + grp->data = devm_kcalloc(ipctl->dev, + grp->num_pins, sizeof(struct imx_pin), + GFP_KERNEL); + grp->pins = devm_kcalloc(ipctl->dev, + grp->num_pins, sizeof(unsigned int), + GFP_KERNEL); if (!grp->pins || !grp->data) return -ENOMEM; @@ -697,8 +700,9 @@ int imx_pinctrl_probe(struct platform_device *pdev, if (!ipctl) return -ENOMEM; - ipctl->pin_regs = devm_kmalloc(&pdev->dev, sizeof(*ipctl->pin_regs) * - info->npins, GFP_KERNEL); + ipctl->pin_regs = devm_kmalloc_array(&pdev->dev, + info->npins, sizeof(*ipctl->pin_regs), + GFP_KERNEL); if (!ipctl->pin_regs) return -ENOMEM; diff --git a/drivers/pinctrl/freescale/pinctrl-imx1-core.c b/drivers/pinctrl/freescale/pinctrl-imx1-core.c index 5af89de0ff02..c3bdd90b1422 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx1-core.c +++ b/drivers/pinctrl/freescale/pinctrl-imx1-core.c @@ -241,7 +241,8 @@ static int imx1_dt_node_to_map(struct pinctrl_dev *pctldev, for (i = 0; i < grp->npins; i++) map_num++; - new_map = kmalloc(sizeof(struct pinctrl_map) * map_num, GFP_KERNEL); + new_map = kmalloc_array(map_num, sizeof(struct pinctrl_map), + GFP_KERNEL); if (!new_map) return -ENOMEM; @@ -482,10 +483,10 @@ static int imx1_pinctrl_parse_groups(struct device_node *np, } grp->npins = size / 12; - grp->pins = devm_kzalloc(info->dev, - grp->npins * sizeof(struct imx1_pin), GFP_KERNEL); - grp->pin_ids = devm_kzalloc(info->dev, - grp->npins * sizeof(unsigned int), GFP_KERNEL); + grp->pins = devm_kcalloc(info->dev, + grp->npins, sizeof(struct imx1_pin), GFP_KERNEL); + grp->pin_ids = devm_kcalloc(info->dev, + grp->npins, sizeof(unsigned int), GFP_KERNEL); if (!grp->pins || !grp->pin_ids) return -ENOMEM; @@ -522,8 +523,8 @@ static int imx1_pinctrl_parse_functions(struct device_node *np, if (func->num_groups == 0) return -EINVAL; - func->groups = devm_kzalloc(info->dev, - func->num_groups * sizeof(char *), GFP_KERNEL); + func->groups = devm_kcalloc(info->dev, + func->num_groups, sizeof(char *), GFP_KERNEL); if (!func->groups) return -ENOMEM; @@ -565,12 +566,12 @@ static int imx1_pinctrl_parse_dt(struct platform_device *pdev, } info->nfunctions = nfuncs; - info->functions = devm_kzalloc(&pdev->dev, - nfuncs * sizeof(struct imx1_pmx_func), GFP_KERNEL); + info->functions = devm_kcalloc(&pdev->dev, + nfuncs, sizeof(struct imx1_pmx_func), GFP_KERNEL); info->ngroups = ngroups; - info->groups = devm_kzalloc(&pdev->dev, - ngroups * sizeof(struct imx1_pin_group), GFP_KERNEL); + info->groups = devm_kcalloc(&pdev->dev, + ngroups, sizeof(struct imx1_pin_group), GFP_KERNEL); if (!info->functions || !info->groups) diff --git a/drivers/pinctrl/freescale/pinctrl-mxs.c b/drivers/pinctrl/freescale/pinctrl-mxs.c index 594f3e5ce9a9..a612e46ca51c 100644 --- a/drivers/pinctrl/freescale/pinctrl-mxs.c +++ b/drivers/pinctrl/freescale/pinctrl-mxs.c @@ -89,7 +89,7 @@ static int mxs_dt_node_to_map(struct pinctrl_dev *pctldev, if (!purecfg && config) new_num = 2; - new_map = kzalloc(sizeof(*new_map) * new_num, GFP_KERNEL); + new_map = kcalloc(new_num, sizeof(*new_map), GFP_KERNEL); if (!new_map) return -ENOMEM; @@ -370,12 +370,12 @@ static int mxs_pinctrl_parse_group(struct platform_device *pdev, return -EINVAL; g->npins = length / sizeof(u32); - g->pins = devm_kzalloc(&pdev->dev, g->npins * sizeof(*g->pins), + g->pins = devm_kcalloc(&pdev->dev, g->npins, sizeof(*g->pins), GFP_KERNEL); if (!g->pins) return -ENOMEM; - g->muxsel = devm_kzalloc(&pdev->dev, g->npins * sizeof(*g->muxsel), + g->muxsel = devm_kcalloc(&pdev->dev, g->npins, sizeof(*g->muxsel), GFP_KERNEL); if (!g->muxsel) return -ENOMEM; @@ -426,13 +426,16 @@ static int mxs_pinctrl_probe_dt(struct platform_device *pdev, } } - soc->functions = devm_kzalloc(&pdev->dev, soc->nfunctions * - sizeof(*soc->functions), GFP_KERNEL); + soc->functions = devm_kcalloc(&pdev->dev, + soc->nfunctions, + sizeof(*soc->functions), + GFP_KERNEL); if (!soc->functions) return -ENOMEM; - soc->groups = devm_kzalloc(&pdev->dev, soc->ngroups * - sizeof(*soc->groups), GFP_KERNEL); + soc->groups = devm_kcalloc(&pdev->dev, + soc->ngroups, sizeof(*soc->groups), + GFP_KERNEL); if (!soc->groups) return -ENOMEM; @@ -492,7 +495,8 @@ static int mxs_pinctrl_probe_dt(struct platform_device *pdev, if (strcmp(fn, child->name)) { f = &soc->functions[idxf++]; - f->groups = devm_kzalloc(&pdev->dev, f->ngroups * + f->groups = devm_kcalloc(&pdev->dev, + f->ngroups, sizeof(*f->groups), GFP_KERNEL); if (!f->groups) diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c index 674ffdf8103c..53cf800688e9 100644 --- a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +++ b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c @@ -856,9 +856,10 @@ static int armada_37xx_fill_group(struct armada_37xx_pinctrl *info) struct armada_37xx_pin_group *grp = &info->groups[n]; int i, j, f; - grp->pins = devm_kzalloc(info->dev, - (grp->npins + grp->extra_npins) * - sizeof(*grp->pins), GFP_KERNEL); + grp->pins = devm_kcalloc(info->dev, + grp->npins + grp->extra_npins, + sizeof(*grp->pins), + GFP_KERNEL); if (!grp->pins) return -ENOMEM; @@ -908,7 +909,8 @@ static int armada_37xx_fill_func(struct armada_37xx_pinctrl *info) const char **groups; int g; - funcs[n].groups = devm_kzalloc(info->dev, funcs[n].ngroups * + funcs[n].groups = devm_kcalloc(info->dev, + funcs[n].ngroups, sizeof(*(funcs[n].groups)), GFP_KERNEL); if (!funcs[n].groups) @@ -948,8 +950,9 @@ static int armada_37xx_pinctrl_register(struct platform_device *pdev, ctrldesc->pmxops = &armada_37xx_pmx_ops; ctrldesc->confops = &armada_37xx_pinconf_ops; - pindesc = devm_kzalloc(&pdev->dev, sizeof(*pindesc) * - pin_data->nr_pins, GFP_KERNEL); + pindesc = devm_kcalloc(&pdev->dev, + pin_data->nr_pins, sizeof(*pindesc), + GFP_KERNEL); if (!pindesc) return -ENOMEM; @@ -968,8 +971,10 @@ static int armada_37xx_pinctrl_register(struct platform_device *pdev, * we allocate functions for number of pins and hope there are * fewer unique functions than pins available */ - info->funcs = devm_kzalloc(&pdev->dev, pin_data->nr_pins * - sizeof(struct armada_37xx_pmx_func), GFP_KERNEL); + info->funcs = devm_kcalloc(&pdev->dev, + pin_data->nr_pins, + sizeof(struct armada_37xx_pmx_func), + GFP_KERNEL); if (!info->funcs) return -ENOMEM; diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-xp.c b/drivers/pinctrl/mvebu/pinctrl-armada-xp.c index 5e828468e43d..43231fd065a1 100644 --- a/drivers/pinctrl/mvebu/pinctrl-armada-xp.c +++ b/drivers/pinctrl/mvebu/pinctrl-armada-xp.c @@ -630,8 +630,8 @@ static int armada_xp_pinctrl_probe(struct platform_device *pdev) nregs = DIV_ROUND_UP(soc->nmodes, MVEBU_MPPS_PER_REG); - mpp_saved_regs = devm_kmalloc(&pdev->dev, nregs * sizeof(u32), - GFP_KERNEL); + mpp_saved_regs = devm_kmalloc_array(&pdev->dev, nregs, sizeof(u32), + GFP_KERNEL); if (!mpp_saved_regs) return -ENOMEM; diff --git a/drivers/pinctrl/mvebu/pinctrl-mvebu.c b/drivers/pinctrl/mvebu/pinctrl-mvebu.c index 9e05cfaf75f0..d7ec7119701b 100644 --- a/drivers/pinctrl/mvebu/pinctrl-mvebu.c +++ b/drivers/pinctrl/mvebu/pinctrl-mvebu.c @@ -501,8 +501,9 @@ static int mvebu_pinctrl_build_functions(struct platform_device *pdev, /* we allocate functions for number of pins and hope * there are fewer unique functions than pins available */ - funcs = devm_kzalloc(&pdev->dev, funcsize * - sizeof(struct mvebu_pinctrl_function), GFP_KERNEL); + funcs = devm_kcalloc(&pdev->dev, + funcsize, sizeof(struct mvebu_pinctrl_function), + GFP_KERNEL); if (!funcs) return -ENOMEM; @@ -549,8 +550,9 @@ static int mvebu_pinctrl_build_functions(struct platform_device *pdev, /* allocate group name array if not done already */ if (!f->groups) { - f->groups = devm_kzalloc(&pdev->dev, - f->num_groups * sizeof(char *), + f->groups = devm_kcalloc(&pdev->dev, + f->num_groups, + sizeof(char *), GFP_KERNEL); if (!f->groups) return -ENOMEM; @@ -622,8 +624,10 @@ int mvebu_pinctrl_probe(struct platform_device *pdev) } } - pdesc = devm_kzalloc(&pdev->dev, pctl->desc.npins * - sizeof(struct pinctrl_pin_desc), GFP_KERNEL); + pdesc = devm_kcalloc(&pdev->dev, + pctl->desc.npins, + sizeof(struct pinctrl_pin_desc), + GFP_KERNEL); if (!pdesc) return -ENOMEM; diff --git a/drivers/pinctrl/pinctrl-at91-pio4.c b/drivers/pinctrl/pinctrl-at91-pio4.c index bafb3d40545e..67e4d9ffa6b1 100644 --- a/drivers/pinctrl/pinctrl-at91-pio4.c +++ b/drivers/pinctrl/pinctrl-at91-pio4.c @@ -945,27 +945,30 @@ static int atmel_pinctrl_probe(struct platform_device *pdev) return PTR_ERR(atmel_pioctrl->clk); } - atmel_pioctrl->pins = devm_kzalloc(dev, sizeof(*atmel_pioctrl->pins) - * atmel_pioctrl->npins, GFP_KERNEL); + atmel_pioctrl->pins = devm_kcalloc(dev, + atmel_pioctrl->npins, + sizeof(*atmel_pioctrl->pins), + GFP_KERNEL); if (!atmel_pioctrl->pins) return -ENOMEM; - pin_desc = devm_kzalloc(dev, sizeof(*pin_desc) - * atmel_pioctrl->npins, GFP_KERNEL); + pin_desc = devm_kcalloc(dev, atmel_pioctrl->npins, sizeof(*pin_desc), + GFP_KERNEL); if (!pin_desc) return -ENOMEM; atmel_pinctrl_desc.pins = pin_desc; atmel_pinctrl_desc.npins = atmel_pioctrl->npins; /* One pin is one group since a pin can achieve all functions. */ - group_names = devm_kzalloc(dev, sizeof(*group_names) - * atmel_pioctrl->npins, GFP_KERNEL); + group_names = devm_kcalloc(dev, + atmel_pioctrl->npins, sizeof(*group_names), + GFP_KERNEL); if (!group_names) return -ENOMEM; atmel_pioctrl->group_names = group_names; - atmel_pioctrl->groups = devm_kzalloc(&pdev->dev, - sizeof(*atmel_pioctrl->groups) * atmel_pioctrl->npins, + atmel_pioctrl->groups = devm_kcalloc(&pdev->dev, + atmel_pioctrl->npins, sizeof(*atmel_pioctrl->groups), GFP_KERNEL); if (!atmel_pioctrl->groups) return -ENOMEM; @@ -1001,20 +1004,24 @@ static int atmel_pinctrl_probe(struct platform_device *pdev) atmel_pioctrl->gpio_chip->parent = dev; atmel_pioctrl->gpio_chip->names = atmel_pioctrl->group_names; - atmel_pioctrl->pm_wakeup_sources = devm_kzalloc(dev, - sizeof(*atmel_pioctrl->pm_wakeup_sources) - * atmel_pioctrl->nbanks, GFP_KERNEL); + atmel_pioctrl->pm_wakeup_sources = devm_kcalloc(dev, + atmel_pioctrl->nbanks, + sizeof(*atmel_pioctrl->pm_wakeup_sources), + GFP_KERNEL); if (!atmel_pioctrl->pm_wakeup_sources) return -ENOMEM; - atmel_pioctrl->pm_suspend_backup = devm_kzalloc(dev, - sizeof(*atmel_pioctrl->pm_suspend_backup) - * atmel_pioctrl->nbanks, GFP_KERNEL); + atmel_pioctrl->pm_suspend_backup = devm_kcalloc(dev, + atmel_pioctrl->nbanks, + sizeof(*atmel_pioctrl->pm_suspend_backup), + GFP_KERNEL); if (!atmel_pioctrl->pm_suspend_backup) return -ENOMEM; - atmel_pioctrl->irqs = devm_kzalloc(dev, sizeof(*atmel_pioctrl->irqs) - * atmel_pioctrl->nbanks, GFP_KERNEL); + atmel_pioctrl->irqs = devm_kcalloc(dev, + atmel_pioctrl->nbanks, + sizeof(*atmel_pioctrl->irqs), + GFP_KERNEL); if (!atmel_pioctrl->irqs) return -ENOMEM; diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c index 297f1d161211..50f0ec42c637 100644 --- a/drivers/pinctrl/pinctrl-at91.c +++ b/drivers/pinctrl/pinctrl-at91.c @@ -269,7 +269,8 @@ static int at91_dt_node_to_map(struct pinctrl_dev *pctldev, } map_num += grp->npins; - new_map = devm_kzalloc(pctldev->dev, sizeof(*new_map) * map_num, GFP_KERNEL); + new_map = devm_kcalloc(pctldev->dev, map_num, sizeof(*new_map), + GFP_KERNEL); if (!new_map) return -ENOMEM; @@ -1049,7 +1050,8 @@ static int at91_pinctrl_mux_mask(struct at91_pinctrl *info, } info->nmux = size / gpio_banks; - info->mux_mask = devm_kzalloc(info->dev, sizeof(u32) * size, GFP_KERNEL); + info->mux_mask = devm_kcalloc(info->dev, size, sizeof(u32), + GFP_KERNEL); if (!info->mux_mask) return -ENOMEM; @@ -1087,10 +1089,12 @@ static int at91_pinctrl_parse_groups(struct device_node *np, } grp->npins = size / 4; - pin = grp->pins_conf = devm_kzalloc(info->dev, grp->npins * sizeof(struct at91_pmx_pin), - GFP_KERNEL); - grp->pins = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int), - GFP_KERNEL); + pin = grp->pins_conf = devm_kcalloc(info->dev, + grp->npins, + sizeof(struct at91_pmx_pin), + GFP_KERNEL); + grp->pins = devm_kcalloc(info->dev, grp->npins, sizeof(unsigned int), + GFP_KERNEL); if (!grp->pins_conf || !grp->pins) return -ENOMEM; @@ -1129,8 +1133,8 @@ static int at91_pinctrl_parse_functions(struct device_node *np, dev_err(info->dev, "no groups defined\n"); return -EINVAL; } - func->groups = devm_kzalloc(info->dev, - func->ngroups * sizeof(char *), GFP_KERNEL); + func->groups = devm_kcalloc(info->dev, + func->ngroups, sizeof(char *), GFP_KERNEL); if (!func->groups) return -ENOMEM; @@ -1192,12 +1196,16 @@ static int at91_pinctrl_probe_dt(struct platform_device *pdev, dev_dbg(&pdev->dev, "nfunctions = %d\n", info->nfunctions); dev_dbg(&pdev->dev, "ngroups = %d\n", info->ngroups); - info->functions = devm_kzalloc(&pdev->dev, info->nfunctions * sizeof(struct at91_pmx_func), + info->functions = devm_kcalloc(&pdev->dev, + info->nfunctions, + sizeof(struct at91_pmx_func), GFP_KERNEL); if (!info->functions) return -ENOMEM; - info->groups = devm_kzalloc(&pdev->dev, info->ngroups * sizeof(struct at91_pin_group), + info->groups = devm_kcalloc(&pdev->dev, + info->ngroups, + sizeof(struct at91_pin_group), GFP_KERNEL); if (!info->groups) return -ENOMEM; @@ -1256,7 +1264,9 @@ static int at91_pinctrl_probe(struct platform_device *pdev) at91_pinctrl_desc.name = dev_name(&pdev->dev); at91_pinctrl_desc.npins = gpio_banks * MAX_NB_GPIO_PER_BANK; at91_pinctrl_desc.pins = pdesc = - devm_kzalloc(&pdev->dev, sizeof(*pdesc) * at91_pinctrl_desc.npins, GFP_KERNEL); + devm_kcalloc(&pdev->dev, + at91_pinctrl_desc.npins, sizeof(*pdesc), + GFP_KERNEL); if (!at91_pinctrl_desc.pins) return -ENOMEM; @@ -1763,7 +1773,7 @@ static int at91_gpio_probe(struct platform_device *pdev) chip->ngpio = ngpio; } - names = devm_kzalloc(&pdev->dev, sizeof(char *) * chip->ngpio, + names = devm_kcalloc(&pdev->dev, chip->ngpio, sizeof(char *), GFP_KERNEL); if (!names) { diff --git a/drivers/pinctrl/pinctrl-axp209.c b/drivers/pinctrl/pinctrl-axp209.c index 1231bbbfa744..a52779f33ad4 100644 --- a/drivers/pinctrl/pinctrl-axp209.c +++ b/drivers/pinctrl/pinctrl-axp209.c @@ -328,7 +328,8 @@ static void axp20x_funcs_groups_from_mask(struct device *dev, unsigned int mask, func->ngroups = ngroups; if (func->ngroups > 0) { - func->groups = devm_kzalloc(dev, ngroups * sizeof(const char *), + func->groups = devm_kcalloc(dev, + ngroups, sizeof(const char *), GFP_KERNEL); group = func->groups; for_each_set_bit(bit, &mask_cpy, mask_len) { @@ -358,8 +359,8 @@ static void axp20x_build_funcs_groups(struct platform_device *pdev) /* Every pin supports GPIO_OUT and GPIO_IN functions */ for (i = 0; i <= AXP20X_FUNC_GPIO_IN; i++) { pctl->funcs[i].ngroups = npins; - pctl->funcs[i].groups = devm_kzalloc(&pdev->dev, - npins * sizeof(char *), + pctl->funcs[i].groups = devm_kcalloc(&pdev->dev, + npins, sizeof(char *), GFP_KERNEL); for (pin = 0; pin < npins; pin++) pctl->funcs[i].groups[pin] = pctl->desc->pins[pin].name; diff --git a/drivers/pinctrl/pinctrl-digicolor.c b/drivers/pinctrl/pinctrl-digicolor.c index ce269ced4d49..5353b23f775c 100644 --- a/drivers/pinctrl/pinctrl-digicolor.c +++ b/drivers/pinctrl/pinctrl-digicolor.c @@ -291,10 +291,11 @@ static int dc_pinctrl_probe(struct platform_device *pdev) if (IS_ERR(pmap->regs)) return PTR_ERR(pmap->regs); - pins = devm_kzalloc(&pdev->dev, sizeof(*pins)*PINS_COUNT, GFP_KERNEL); + pins = devm_kcalloc(&pdev->dev, PINS_COUNT, sizeof(*pins), + GFP_KERNEL); if (!pins) return -ENOMEM; - pin_names = devm_kzalloc(&pdev->dev, name_len * PINS_COUNT, + pin_names = devm_kcalloc(&pdev->dev, PINS_COUNT, name_len, GFP_KERNEL); if (!pin_names) return -ENOMEM; diff --git a/drivers/pinctrl/pinctrl-ingenic.c b/drivers/pinctrl/pinctrl-ingenic.c index ac38a3f9f86b..a1d7156d0a43 100644 --- a/drivers/pinctrl/pinctrl-ingenic.c +++ b/drivers/pinctrl/pinctrl-ingenic.c @@ -770,8 +770,8 @@ static int ingenic_pinctrl_probe(struct platform_device *pdev) pctl_desc->pmxops = &ingenic_pmxops; pctl_desc->confops = &ingenic_confops; pctl_desc->npins = chip_info->num_chips * PINS_PER_GPIO_CHIP; - pctl_desc->pins = jzpc->pdesc = devm_kzalloc(&pdev->dev, - sizeof(*jzpc->pdesc) * pctl_desc->npins, GFP_KERNEL); + pctl_desc->pins = jzpc->pdesc = devm_kcalloc(&pdev->dev, + pctl_desc->npins, sizeof(*jzpc->pdesc), GFP_KERNEL); if (!jzpc->pdesc) return -ENOMEM; diff --git a/drivers/pinctrl/pinctrl-lantiq.c b/drivers/pinctrl/pinctrl-lantiq.c index 41dc39c7a7b1..81632af3a86a 100644 --- a/drivers/pinctrl/pinctrl-lantiq.c +++ b/drivers/pinctrl/pinctrl-lantiq.c @@ -158,7 +158,8 @@ static int ltq_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, for_each_child_of_node(np_config, np) max_maps += ltq_pinctrl_dt_subnode_size(np); - *map = kzalloc(max_maps * sizeof(struct pinctrl_map) * 2, GFP_KERNEL); + *map = kzalloc(array3_size(max_maps, sizeof(struct pinctrl_map), 2), + GFP_KERNEL); if (!*map) return -ENOMEM; tmp = *map; diff --git a/drivers/pinctrl/pinctrl-lpc18xx.c b/drivers/pinctrl/pinctrl-lpc18xx.c index d090f37ca4a1..190f17e4bbda 100644 --- a/drivers/pinctrl/pinctrl-lpc18xx.c +++ b/drivers/pinctrl/pinctrl-lpc18xx.c @@ -1308,8 +1308,9 @@ static int lpc18xx_create_group_func_map(struct device *dev, } scu->func[func].ngroups = ngroups; - scu->func[func].groups = devm_kzalloc(dev, ngroups * - sizeof(char *), GFP_KERNEL); + scu->func[func].groups = devm_kcalloc(dev, + ngroups, sizeof(char *), + GFP_KERNEL); if (!scu->func[func].groups) return -ENOMEM; diff --git a/drivers/pinctrl/pinctrl-ocelot.c b/drivers/pinctrl/pinctrl-ocelot.c index b5b3547fdcb2..15bb1cb8729b 100644 --- a/drivers/pinctrl/pinctrl-ocelot.c +++ b/drivers/pinctrl/pinctrl-ocelot.c @@ -330,7 +330,8 @@ static int ocelot_create_group_func_map(struct device *dev, } info->func[f].ngroups = npins; - info->func[f].groups = devm_kzalloc(dev, npins * + info->func[f].groups = devm_kcalloc(dev, + npins, sizeof(char *), GFP_KERNEL); if (!info->func[f].groups) diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 1882713e68f9..f4a61429e06e 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -507,7 +507,7 @@ static int rockchip_dt_node_to_map(struct pinctrl_dev *pctldev, } map_num += grp->npins; - new_map = devm_kzalloc(pctldev->dev, sizeof(*new_map) * map_num, + new_map = devm_kcalloc(pctldev->dev, map_num, sizeof(*new_map), GFP_KERNEL); if (!new_map) return -ENOMEM; @@ -2473,10 +2473,11 @@ static int rockchip_pinctrl_parse_groups(struct device_node *np, grp->npins = size / 4; - grp->pins = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int), + grp->pins = devm_kcalloc(info->dev, grp->npins, sizeof(unsigned int), GFP_KERNEL); - grp->data = devm_kzalloc(info->dev, grp->npins * - sizeof(struct rockchip_pin_config), + grp->data = devm_kcalloc(info->dev, + grp->npins, + sizeof(struct rockchip_pin_config), GFP_KERNEL); if (!grp->pins || !grp->data) return -ENOMEM; @@ -2528,8 +2529,8 @@ static int rockchip_pinctrl_parse_functions(struct device_node *np, if (func->ngroups <= 0) return 0; - func->groups = devm_kzalloc(info->dev, - func->ngroups * sizeof(char *), GFP_KERNEL); + func->groups = devm_kcalloc(info->dev, + func->ngroups, sizeof(char *), GFP_KERNEL); if (!func->groups) return -ENOMEM; @@ -2560,13 +2561,15 @@ static int rockchip_pinctrl_parse_dt(struct platform_device *pdev, dev_dbg(&pdev->dev, "nfunctions = %d\n", info->nfunctions); dev_dbg(&pdev->dev, "ngroups = %d\n", info->ngroups); - info->functions = devm_kzalloc(dev, info->nfunctions * + info->functions = devm_kcalloc(dev, + info->nfunctions, sizeof(struct rockchip_pmx_func), GFP_KERNEL); if (!info->functions) return -EINVAL; - info->groups = devm_kzalloc(dev, info->ngroups * + info->groups = devm_kcalloc(dev, + info->ngroups, sizeof(struct rockchip_pin_group), GFP_KERNEL); if (!info->groups) @@ -2604,8 +2607,9 @@ static int rockchip_pinctrl_register(struct platform_device *pdev, ctrldesc->pmxops = &rockchip_pmx_ops; ctrldesc->confops = &rockchip_pinconf_ops; - pindesc = devm_kzalloc(&pdev->dev, sizeof(*pindesc) * - info->ctrl->nr_pins, GFP_KERNEL); + pindesc = devm_kcalloc(&pdev->dev, + info->ctrl->nr_pins, sizeof(*pindesc), + GFP_KERNEL); if (!pindesc) return -ENOMEM; diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 9c3c00515aa0..b3153c095199 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -712,8 +712,8 @@ static int pcs_allocate_pin_table(struct pcs_device *pcs) } dev_dbg(pcs->dev, "allocating %i pins\n", nr_pins); - pcs->pins.pa = devm_kzalloc(pcs->dev, - sizeof(*pcs->pins.pa) * nr_pins, + pcs->pins.pa = devm_kcalloc(pcs->dev, + nr_pins, sizeof(*pcs->pins.pa), GFP_KERNEL); if (!pcs->pins.pa) return -ENOMEM; @@ -924,15 +924,15 @@ static int pcs_parse_pinconf(struct pcs_device *pcs, struct device_node *np, if (!nconfs) return 0; - func->conf = devm_kzalloc(pcs->dev, - sizeof(struct pcs_conf_vals) * nconfs, + func->conf = devm_kcalloc(pcs->dev, + nconfs, sizeof(struct pcs_conf_vals), GFP_KERNEL); if (!func->conf) return -ENOMEM; func->nconfs = nconfs; conf = &(func->conf[0]); m++; - settings = devm_kzalloc(pcs->dev, sizeof(unsigned long) * nconfs, + settings = devm_kcalloc(pcs->dev, nconfs, sizeof(unsigned long), GFP_KERNEL); if (!settings) return -ENOMEM; @@ -988,11 +988,11 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs, return -EINVAL; } - vals = devm_kzalloc(pcs->dev, sizeof(*vals) * rows, GFP_KERNEL); + vals = devm_kcalloc(pcs->dev, rows, sizeof(*vals), GFP_KERNEL); if (!vals) return -ENOMEM; - pins = devm_kzalloc(pcs->dev, sizeof(*pins) * rows, GFP_KERNEL); + pins = devm_kcalloc(pcs->dev, rows, sizeof(*pins), GFP_KERNEL); if (!pins) goto free_vals; @@ -1089,13 +1089,15 @@ static int pcs_parse_bits_in_pinctrl_entry(struct pcs_device *pcs, npins_in_row = pcs->width / pcs->bits_per_pin; - vals = devm_kzalloc(pcs->dev, sizeof(*vals) * rows * npins_in_row, - GFP_KERNEL); + vals = devm_kzalloc(pcs->dev, + array3_size(rows, npins_in_row, sizeof(*vals)), + GFP_KERNEL); if (!vals) return -ENOMEM; - pins = devm_kzalloc(pcs->dev, sizeof(*pins) * rows * npins_in_row, - GFP_KERNEL); + pins = devm_kzalloc(pcs->dev, + array3_size(rows, npins_in_row, sizeof(*pins)), + GFP_KERNEL); if (!pins) goto free_vals; @@ -1217,7 +1219,7 @@ static int pcs_dt_node_to_map(struct pinctrl_dev *pctldev, pcs = pinctrl_dev_get_drvdata(pctldev); /* create 2 maps. One is for pinmux, and the other is for pinconf. */ - *map = devm_kzalloc(pcs->dev, sizeof(**map) * 2, GFP_KERNEL); + *map = devm_kcalloc(pcs->dev, 2, sizeof(**map), GFP_KERNEL); if (!*map) return -ENOMEM; diff --git a/drivers/pinctrl/pinctrl-st.c b/drivers/pinctrl/pinctrl-st.c index 2081c67667a8..0966bb0bf71f 100644 --- a/drivers/pinctrl/pinctrl-st.c +++ b/drivers/pinctrl/pinctrl-st.c @@ -823,8 +823,8 @@ static int st_pctl_dt_node_to_map(struct pinctrl_dev *pctldev, } map_num = grp->npins + 1; - new_map = devm_kzalloc(pctldev->dev, - sizeof(*new_map) * map_num, GFP_KERNEL); + new_map = devm_kcalloc(pctldev->dev, + map_num, sizeof(*new_map), GFP_KERNEL); if (!new_map) return -ENOMEM; @@ -1191,9 +1191,9 @@ static int st_pctl_dt_parse_groups(struct device_node *np, grp->npins = npins; grp->name = np->name; - grp->pins = devm_kzalloc(info->dev, npins * sizeof(u32), GFP_KERNEL); - grp->pin_conf = devm_kzalloc(info->dev, - npins * sizeof(*conf), GFP_KERNEL); + grp->pins = devm_kcalloc(info->dev, npins, sizeof(u32), GFP_KERNEL); + grp->pin_conf = devm_kcalloc(info->dev, + npins, sizeof(*conf), GFP_KERNEL); if (!grp->pins || !grp->pin_conf) return -ENOMEM; @@ -1249,8 +1249,8 @@ static int st_pctl_parse_functions(struct device_node *np, dev_err(info->dev, "No groups defined\n"); return -EINVAL; } - func->groups = devm_kzalloc(info->dev, - func->ngroups * sizeof(char *), GFP_KERNEL); + func->groups = devm_kcalloc(info->dev, + func->ngroups, sizeof(char *), GFP_KERNEL); if (!func->groups) return -ENOMEM; @@ -1573,14 +1573,15 @@ static int st_pctl_probe_dt(struct platform_device *pdev, dev_info(&pdev->dev, "nfunctions = %d\n", info->nfunctions); dev_info(&pdev->dev, "ngroups = %d\n", info->ngroups); - info->functions = devm_kzalloc(&pdev->dev, - info->nfunctions * sizeof(*info->functions), GFP_KERNEL); + info->functions = devm_kcalloc(&pdev->dev, + info->nfunctions, sizeof(*info->functions), GFP_KERNEL); - info->groups = devm_kzalloc(&pdev->dev, - info->ngroups * sizeof(*info->groups) , GFP_KERNEL); + info->groups = devm_kcalloc(&pdev->dev, + info->ngroups, sizeof(*info->groups), + GFP_KERNEL); - info->banks = devm_kzalloc(&pdev->dev, - info->nbanks * sizeof(*info->banks), GFP_KERNEL); + info->banks = devm_kcalloc(&pdev->dev, + info->nbanks, sizeof(*info->banks), GFP_KERNEL); if (!info->functions || !info->groups || !info->banks) return -ENOMEM; @@ -1608,8 +1609,8 @@ static int st_pctl_probe_dt(struct platform_device *pdev, } pctl_desc->npins = info->nbanks * ST_GPIO_PINS_PER_BANK; - pdesc = devm_kzalloc(&pdev->dev, - sizeof(*pdesc) * pctl_desc->npins, GFP_KERNEL); + pdesc = devm_kcalloc(&pdev->dev, + pctl_desc->npins, sizeof(*pdesc), GFP_KERNEL); if (!pdesc) return -ENOMEM; diff --git a/drivers/pinctrl/pinctrl-xway.c b/drivers/pinctrl/pinctrl-xway.c index cd0f402c1164..93f8bd04e7fe 100644 --- a/drivers/pinctrl/pinctrl-xway.c +++ b/drivers/pinctrl/pinctrl-xway.c @@ -1727,8 +1727,8 @@ static int pinmux_xway_probe(struct platform_device *pdev) xway_chip.ngpio = xway_soc->pin_count; /* load our pad descriptors */ - xway_info.pads = devm_kzalloc(&pdev->dev, - sizeof(struct pinctrl_pin_desc) * xway_chip.ngpio, + xway_info.pads = devm_kcalloc(&pdev->dev, + xway_chip.ngpio, sizeof(struct pinctrl_pin_desc), GFP_KERNEL); if (!xway_info.pads) return -ENOMEM; diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c index 0a625a64ff5d..a263ddd94945 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos.c @@ -491,8 +491,9 @@ int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d) continue; } - weint_data = devm_kzalloc(dev, bank->nr_pins - * sizeof(*weint_data), GFP_KERNEL); + weint_data = devm_kcalloc(dev, + bank->nr_pins, sizeof(*weint_data), + GFP_KERNEL); if (!weint_data) return -ENOMEM; diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c index 618945a0fd38..698c7d8c9a08 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.c +++ b/drivers/pinctrl/samsung/pinctrl-samsung.c @@ -674,7 +674,7 @@ static struct samsung_pin_group *samsung_pinctrl_create_groups( const struct pinctrl_pin_desc *pdesc; int i; - groups = devm_kzalloc(dev, ctrldesc->npins * sizeof(*groups), + groups = devm_kcalloc(dev, ctrldesc->npins, sizeof(*groups), GFP_KERNEL); if (!groups) return ERR_PTR(-EINVAL); @@ -711,7 +711,7 @@ static int samsung_pinctrl_create_function(struct device *dev, func->name = func_np->full_name; - func->groups = devm_kzalloc(dev, npins * sizeof(char *), GFP_KERNEL); + func->groups = devm_kcalloc(dev, npins, sizeof(char *), GFP_KERNEL); if (!func->groups) return -ENOMEM; @@ -768,7 +768,7 @@ static struct samsung_pmx_func *samsung_pinctrl_create_functions( } } - functions = devm_kzalloc(dev, func_cnt * sizeof(*functions), + functions = devm_kcalloc(dev, func_cnt, sizeof(*functions), GFP_KERNEL); if (!functions) return ERR_PTR(-ENOMEM); @@ -860,8 +860,9 @@ static int samsung_pinctrl_register(struct platform_device *pdev, ctrldesc->pmxops = &samsung_pinmux_ops; ctrldesc->confops = &samsung_pinconf_ops; - pindesc = devm_kzalloc(&pdev->dev, sizeof(*pindesc) * - drvdata->nr_pins, GFP_KERNEL); + pindesc = devm_kcalloc(&pdev->dev, + drvdata->nr_pins, sizeof(*pindesc), + GFP_KERNEL); if (!pindesc) return -ENOMEM; ctrldesc->pins = pindesc; @@ -875,8 +876,10 @@ static int samsung_pinctrl_register(struct platform_device *pdev, * allocate space for storing the dynamically generated names for all * the pins which belong to this pin-controller. */ - pin_names = devm_kzalloc(&pdev->dev, sizeof(char) * PIN_NAME_LENGTH * - drvdata->nr_pins, GFP_KERNEL); + pin_names = devm_kzalloc(&pdev->dev, + array3_size(sizeof(char), PIN_NAME_LENGTH, + drvdata->nr_pins), + GFP_KERNEL); if (!pin_names) return -ENOMEM; diff --git a/drivers/pinctrl/sh-pfc/core.c b/drivers/pinctrl/sh-pfc/core.c index eb06981538b4..c671c3c4aca6 100644 --- a/drivers/pinctrl/sh-pfc/core.c +++ b/drivers/pinctrl/sh-pfc/core.c @@ -57,7 +57,7 @@ static int sh_pfc_map_resources(struct sh_pfc *pfc, return -EINVAL; /* Allocate memory windows and IRQs arrays. */ - windows = devm_kzalloc(pfc->dev, num_windows * sizeof(*windows), + windows = devm_kcalloc(pfc->dev, num_windows, sizeof(*windows), GFP_KERNEL); if (windows == NULL) return -ENOMEM; @@ -66,7 +66,7 @@ static int sh_pfc_map_resources(struct sh_pfc *pfc, pfc->windows = windows; if (num_irqs) { - irqs = devm_kzalloc(pfc->dev, num_irqs * sizeof(*irqs), + irqs = devm_kcalloc(pfc->dev, num_irqs, sizeof(*irqs), GFP_KERNEL); if (irqs == NULL) return -ENOMEM; @@ -444,7 +444,7 @@ static int sh_pfc_init_ranges(struct sh_pfc *pfc) } pfc->nr_ranges = nr_ranges; - pfc->ranges = devm_kzalloc(pfc->dev, sizeof(*pfc->ranges) * nr_ranges, + pfc->ranges = devm_kcalloc(pfc->dev, nr_ranges, sizeof(*pfc->ranges), GFP_KERNEL); if (pfc->ranges == NULL) return -ENOMEM; diff --git a/drivers/pinctrl/sh-pfc/gpio.c b/drivers/pinctrl/sh-pfc/gpio.c index 946d9be50b62..6ffdc6beb203 100644 --- a/drivers/pinctrl/sh-pfc/gpio.c +++ b/drivers/pinctrl/sh-pfc/gpio.c @@ -107,7 +107,7 @@ static int gpio_setup_data_regs(struct sh_pfc_chip *chip) for (i = 0; pfc->info->data_regs[i].reg_width; ++i) ; - chip->regs = devm_kzalloc(pfc->dev, i * sizeof(*chip->regs), + chip->regs = devm_kcalloc(pfc->dev, i, sizeof(*chip->regs), GFP_KERNEL); if (chip->regs == NULL) return -ENOMEM; @@ -224,8 +224,9 @@ static int gpio_pin_setup(struct sh_pfc_chip *chip) struct gpio_chip *gc = &chip->gpio_chip; int ret; - chip->pins = devm_kzalloc(pfc->dev, pfc->info->nr_pins * - sizeof(*chip->pins), GFP_KERNEL); + chip->pins = devm_kcalloc(pfc->dev, + pfc->info->nr_pins, sizeof(*chip->pins), + GFP_KERNEL); if (chip->pins == NULL) return -ENOMEM; diff --git a/drivers/pinctrl/sh-pfc/pinctrl.c b/drivers/pinctrl/sh-pfc/pinctrl.c index 70db21638901..654dc20e171b 100644 --- a/drivers/pinctrl/sh-pfc/pinctrl.c +++ b/drivers/pinctrl/sh-pfc/pinctrl.c @@ -770,14 +770,14 @@ static int sh_pfc_map_pins(struct sh_pfc *pfc, struct sh_pfc_pinctrl *pmx) unsigned int i; /* Allocate and initialize the pins and configs arrays. */ - pmx->pins = devm_kzalloc(pfc->dev, - sizeof(*pmx->pins) * pfc->info->nr_pins, + pmx->pins = devm_kcalloc(pfc->dev, + pfc->info->nr_pins, sizeof(*pmx->pins), GFP_KERNEL); if (unlikely(!pmx->pins)) return -ENOMEM; - pmx->configs = devm_kzalloc(pfc->dev, - sizeof(*pmx->configs) * pfc->info->nr_pins, + pmx->configs = devm_kcalloc(pfc->dev, + pfc->info->nr_pins, sizeof(*pmx->configs), GFP_KERNEL); if (unlikely(!pmx->configs)) return -ENOMEM; diff --git a/drivers/pinctrl/sirf/pinctrl-sirf.c b/drivers/pinctrl/sirf/pinctrl-sirf.c index ca2347d0d579..505845c66dd0 100644 --- a/drivers/pinctrl/sirf/pinctrl-sirf.c +++ b/drivers/pinctrl/sirf/pinctrl-sirf.c @@ -108,7 +108,7 @@ static int sirfsoc_dt_node_to_map(struct pinctrl_dev *pctldev, return -ENODEV; } - *map = kzalloc(sizeof(**map) * count, GFP_KERNEL); + *map = kcalloc(count, sizeof(**map), GFP_KERNEL); if (!*map) return -ENOMEM; diff --git a/drivers/pinctrl/spear/pinctrl-plgpio.c b/drivers/pinctrl/spear/pinctrl-plgpio.c index d2123e396b29..9d906474f3e4 100644 --- a/drivers/pinctrl/spear/pinctrl-plgpio.c +++ b/drivers/pinctrl/spear/pinctrl-plgpio.c @@ -538,9 +538,9 @@ static int plgpio_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "clk_get() failed, work without it\n"); #ifdef CONFIG_PM_SLEEP - plgpio->csave_regs = devm_kzalloc(&pdev->dev, - sizeof(*plgpio->csave_regs) * + plgpio->csave_regs = devm_kcalloc(&pdev->dev, DIV_ROUND_UP(plgpio->chip.ngpio, MAX_GPIO_PER_REG), + sizeof(*plgpio->csave_regs), GFP_KERNEL); if (!plgpio->csave_regs) return -ENOMEM; diff --git a/drivers/pinctrl/spear/pinctrl-spear.c b/drivers/pinctrl/spear/pinctrl-spear.c index efe79d3f7659..c4f850345dc4 100644 --- a/drivers/pinctrl/spear/pinctrl-spear.c +++ b/drivers/pinctrl/spear/pinctrl-spear.c @@ -172,7 +172,7 @@ static int spear_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, return -ENODEV; } - *map = kzalloc(sizeof(**map) * count, GFP_KERNEL); + *map = kcalloc(count, sizeof(**map), GFP_KERNEL); if (!*map) return -ENOMEM; diff --git a/drivers/pinctrl/sprd/pinctrl-sprd.c b/drivers/pinctrl/sprd/pinctrl-sprd.c index ba1c2ca406e4..78c2f548b25f 100644 --- a/drivers/pinctrl/sprd/pinctrl-sprd.c +++ b/drivers/pinctrl/sprd/pinctrl-sprd.c @@ -879,8 +879,9 @@ static int sprd_pinctrl_parse_groups(struct device_node *np, grp->name = np->name; grp->npins = ret; - grp->pins = devm_kzalloc(sprd_pctl->dev, grp->npins * - sizeof(unsigned int), GFP_KERNEL); + grp->pins = devm_kcalloc(sprd_pctl->dev, + grp->npins, sizeof(unsigned int), + GFP_KERNEL); if (!grp->pins) return -ENOMEM; @@ -931,14 +932,15 @@ static int sprd_pinctrl_parse_dt(struct sprd_pinctrl *sprd_pctl) if (!info->ngroups) return 0; - info->groups = devm_kzalloc(sprd_pctl->dev, info->ngroups * + info->groups = devm_kcalloc(sprd_pctl->dev, + info->ngroups, sizeof(struct sprd_pin_group), GFP_KERNEL); if (!info->groups) return -ENOMEM; - info->grp_names = devm_kzalloc(sprd_pctl->dev, - info->ngroups * sizeof(char *), + info->grp_names = devm_kcalloc(sprd_pctl->dev, + info->ngroups, sizeof(char *), GFP_KERNEL); if (!info->grp_names) return -ENOMEM; @@ -980,8 +982,8 @@ static int sprd_pinctrl_add_pins(struct sprd_pinctrl *sprd_pctl, int i; info->npins = pins_cnt; - info->pins = devm_kzalloc(sprd_pctl->dev, - info->npins * sizeof(struct sprd_pin), + info->pins = devm_kcalloc(sprd_pctl->dev, + info->npins, sizeof(struct sprd_pin), GFP_KERNEL); if (!info->pins) return -ENOMEM; @@ -1057,7 +1059,8 @@ int sprd_pinctrl_core_probe(struct platform_device *pdev, return ret; } - pin_desc = devm_kzalloc(&pdev->dev, pinctrl_info->npins * + pin_desc = devm_kcalloc(&pdev->dev, + pinctrl_info->npins, sizeof(struct pinctrl_pin_desc), GFP_KERNEL); if (!pin_desc) diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index 25e80a5370ca..4d9bf9b3e9f3 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -277,7 +277,7 @@ static unsigned long *sunxi_pctrl_build_pin_config(struct device_node *node, if (!configlen) return NULL; - pinconfig = kzalloc(configlen * sizeof(*pinconfig), GFP_KERNEL); + pinconfig = kcalloc(configlen, sizeof(*pinconfig), GFP_KERNEL); if (!pinconfig) return ERR_PTR(-ENOMEM); @@ -352,7 +352,7 @@ static int sunxi_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev, * any configuration. */ nmaps = npins * 2; - *map = kmalloc(nmaps * sizeof(struct pinctrl_map), GFP_KERNEL); + *map = kmalloc_array(nmaps, sizeof(struct pinctrl_map), GFP_KERNEL); if (!*map) return -ENOMEM; @@ -1055,8 +1055,8 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev) * this means that the number of pins is the maximum group * number we will ever see. */ - pctl->groups = devm_kzalloc(&pdev->dev, - pctl->desc->npins * sizeof(*pctl->groups), + pctl->groups = devm_kcalloc(&pdev->dev, + pctl->desc->npins, sizeof(*pctl->groups), GFP_KERNEL); if (!pctl->groups) return -ENOMEM; @@ -1079,8 +1079,9 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev) * We suppose that we won't have any more functions than pins, * we'll reallocate that later anyway */ - pctl->functions = devm_kzalloc(&pdev->dev, - pctl->ngroups * sizeof(*pctl->functions), + pctl->functions = devm_kcalloc(&pdev->dev, + pctl->ngroups, + sizeof(*pctl->functions), GFP_KERNEL); if (!pctl->functions) return -ENOMEM; @@ -1137,8 +1138,9 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev) if (!func_item->groups) { func_item->groups = - devm_kzalloc(&pdev->dev, - func_item->ngroups * sizeof(*func_item->groups), + devm_kcalloc(&pdev->dev, + func_item->ngroups, + sizeof(*func_item->groups), GFP_KERNEL); if (!func_item->groups) return -ENOMEM; @@ -1281,8 +1283,8 @@ int sunxi_pinctrl_init_with_variant(struct platform_device *pdev, return ret; } - pins = devm_kzalloc(&pdev->dev, - pctl->desc->npins * sizeof(*pins), + pins = devm_kcalloc(&pdev->dev, + pctl->desc->npins, sizeof(*pins), GFP_KERNEL); if (!pins) return -ENOMEM; diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c index 49c7c1499bc3..f974eee29a19 100644 --- a/drivers/pinctrl/tegra/pinctrl-tegra.c +++ b/drivers/pinctrl/tegra/pinctrl-tegra.c @@ -665,8 +665,8 @@ int tegra_pinctrl_probe(struct platform_device *pdev, * Each mux group will appear in 4 functions' list of groups. * This over-allocates slightly, since not all groups are mux groups. */ - pmx->group_pins = devm_kzalloc(&pdev->dev, - soc_data->ngroups * 4 * sizeof(*pmx->group_pins), + pmx->group_pins = devm_kcalloc(&pdev->dev, + soc_data->ngroups * 4, sizeof(*pmx->group_pins), GFP_KERNEL); if (!pmx->group_pins) return -ENOMEM; @@ -708,7 +708,7 @@ int tegra_pinctrl_probe(struct platform_device *pdev, } pmx->nbanks = i; - pmx->regs = devm_kzalloc(&pdev->dev, pmx->nbanks * sizeof(*pmx->regs), + pmx->regs = devm_kcalloc(&pdev->dev, pmx->nbanks, sizeof(*pmx->regs), GFP_KERNEL); if (!pmx->regs) return -ENOMEM; diff --git a/drivers/pinctrl/ti/pinctrl-ti-iodelay.c b/drivers/pinctrl/ti/pinctrl-ti-iodelay.c index a8a6510183b6..8782c348ebe9 100644 --- a/drivers/pinctrl/ti/pinctrl-ti-iodelay.c +++ b/drivers/pinctrl/ti/pinctrl-ti-iodelay.c @@ -510,11 +510,11 @@ static int ti_iodelay_dt_node_to_map(struct pinctrl_dev *pctldev, goto free_map; } - pins = devm_kzalloc(iod->dev, sizeof(*pins) * rows, GFP_KERNEL); + pins = devm_kcalloc(iod->dev, rows, sizeof(*pins), GFP_KERNEL); if (!pins) goto free_group; - cfg = devm_kzalloc(iod->dev, sizeof(*cfg) * rows, GFP_KERNEL); + cfg = devm_kcalloc(iod->dev, rows, sizeof(*cfg), GFP_KERNEL); if (!cfg) { error = -ENOMEM; goto free_pins; @@ -749,7 +749,7 @@ static int ti_iodelay_alloc_pins(struct device *dev, nr_pins = ti_iodelay_offset_to_pin(iod, r->regmap_config->max_register); dev_dbg(dev, "Allocating %i pins\n", nr_pins); - iod->pa = devm_kzalloc(dev, sizeof(*iod->pa) * nr_pins, GFP_KERNEL); + iod->pa = devm_kcalloc(dev, nr_pins, sizeof(*iod->pa), GFP_KERNEL); if (!iod->pa) return -ENOMEM; diff --git a/drivers/pinctrl/vt8500/pinctrl-wmt.c b/drivers/pinctrl/vt8500/pinctrl-wmt.c index d73956bdc211..c08318a5a91b 100644 --- a/drivers/pinctrl/vt8500/pinctrl-wmt.c +++ b/drivers/pinctrl/vt8500/pinctrl-wmt.c @@ -352,7 +352,7 @@ static int wmt_pctl_dt_node_to_map(struct pinctrl_dev *pctldev, if (num_pulls) maps_per_pin++; - cur_map = maps = kzalloc(num_pins * maps_per_pin * sizeof(*maps), + cur_map = maps = kcalloc(num_pins * maps_per_pin, sizeof(*maps), GFP_KERNEL); if (!maps) return -ENOMEM; diff --git a/drivers/pinctrl/zte/pinctrl-zx.c b/drivers/pinctrl/zte/pinctrl-zx.c index ded366bb6564..caa44dd2880a 100644 --- a/drivers/pinctrl/zte/pinctrl-zx.c +++ b/drivers/pinctrl/zte/pinctrl-zx.c @@ -277,7 +277,7 @@ static int zx_pinctrl_build_state(struct platform_device *pdev) /* Every single pin composes a group */ ngroups = info->npins; - groups = devm_kzalloc(&pdev->dev, ngroups * sizeof(*groups), + groups = devm_kcalloc(&pdev->dev, ngroups, sizeof(*groups), GFP_KERNEL); if (!groups) return -ENOMEM; @@ -362,8 +362,8 @@ static int zx_pinctrl_build_state(struct platform_device *pdev) func = functions + j; if (!func->group_names) { - func->group_names = devm_kzalloc(&pdev->dev, - func->num_group_names * + func->group_names = devm_kcalloc(&pdev->dev, + func->num_group_names, sizeof(*func->group_names), GFP_KERNEL); if (!func->group_names) { diff --git a/drivers/platform/chrome/cros_ec_debugfs.c b/drivers/platform/chrome/cros_ec_debugfs.c index cc265ed8deb7..c62ee8e610a0 100644 --- a/drivers/platform/chrome/cros_ec_debugfs.c +++ b/drivers/platform/chrome/cros_ec_debugfs.c @@ -470,3 +470,23 @@ void cros_ec_debugfs_remove(struct cros_ec_dev *ec) cros_ec_cleanup_console_log(ec->debug_info); } EXPORT_SYMBOL(cros_ec_debugfs_remove); + +void cros_ec_debugfs_suspend(struct cros_ec_dev *ec) +{ + /* + * cros_ec_debugfs_init() failures are non-fatal; it's also possible + * that we initted things but decided that console log wasn't supported. + * We'll use the same set of checks that cros_ec_debugfs_remove() + + * cros_ec_cleanup_console_log() end up using to handle those cases. + */ + if (ec->debug_info && ec->debug_info->log_buffer.buf) + cancel_delayed_work_sync(&ec->debug_info->log_poll_work); +} +EXPORT_SYMBOL(cros_ec_debugfs_suspend); + +void cros_ec_debugfs_resume(struct cros_ec_dev *ec) +{ + if (ec->debug_info && ec->debug_info->log_buffer.buf) + schedule_delayed_work(&ec->debug_info->log_poll_work, 0); +} +EXPORT_SYMBOL(cros_ec_debugfs_resume); diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c index ea9e7f4479ca..ac97aa020db3 100644 --- a/drivers/platform/mellanox/mlxreg-hotplug.c +++ b/drivers/platform/mellanox/mlxreg-hotplug.c @@ -55,13 +55,16 @@ #define MLXREG_HOTPLUG_RST_CNTR 3 #define MLXREG_HOTPLUG_ATTRS_MAX 24 +#define MLXREG_HOTPLUG_NOT_ASSERT 3 /** * struct mlxreg_hotplug_priv_data - platform private data: * @irq: platform device interrupt number; + * @dev: basic device; * @pdev: platform device; * @plat: platform data; - * @dwork: delayed work template; + * @regmap: register map handle; + * @dwork_irq: delayed work template; * @lock: spin lock; * @hwmon: hwmon device; * @mlxreg_hotplug_attr: sysfs attributes array; @@ -71,6 +74,8 @@ * @cell: location of top aggregation interrupt register; * @mask: top aggregation interrupt common mask; * @aggr_cache: last value of aggregation register status; + * @after_probe: flag indication probing completion; + * @not_asserted: number of entries in workqueue with no signal assertion; */ struct mlxreg_hotplug_priv_data { int irq; @@ -79,7 +84,6 @@ struct mlxreg_hotplug_priv_data { struct mlxreg_hotplug_platform_data *plat; struct regmap *regmap; struct delayed_work dwork_irq; - struct delayed_work dwork; spinlock_t lock; /* sync with interrupt */ struct device *hwmon; struct attribute *mlxreg_hotplug_attr[MLXREG_HOTPLUG_ATTRS_MAX + 1]; @@ -91,6 +95,7 @@ struct mlxreg_hotplug_priv_data { u32 mask; u32 aggr_cache; bool after_probe; + u8 not_asserted; }; static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv, @@ -217,7 +222,8 @@ static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv) } } - priv->group.attrs = devm_kzalloc(&priv->pdev->dev, num_attrs * + priv->group.attrs = devm_kcalloc(&priv->pdev->dev, + num_attrs, sizeof(struct attribute *), GFP_KERNEL); if (!priv->group.attrs) @@ -408,6 +414,18 @@ static void mlxreg_hotplug_work_handler(struct work_struct *work) aggr_asserted = priv->aggr_cache ^ regval; priv->aggr_cache = regval; + /* + * Handler is invoked, but no assertion is detected at top aggregation + * status level. Set aggr_asserted to mask value to allow handler extra + * run over all relevant signals to recover any missed signal. + */ + if (priv->not_asserted == MLXREG_HOTPLUG_NOT_ASSERT) { + priv->not_asserted = 0; + aggr_asserted = pdata->mask; + } + if (!aggr_asserted) + goto unmask_event; + /* Handle topology and health configuration changes. */ for (i = 0; i < pdata->counter; i++, item++) { if (aggr_asserted & item->aggr_mask) { @@ -418,27 +436,26 @@ static void mlxreg_hotplug_work_handler(struct work_struct *work) } } - if (aggr_asserted) { - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave(&priv->lock, flags); - /* - * It is possible, that some signals have been inserted, while - * interrupt has been masked by mlxreg_hotplug_work_handler. - * In this case such signals will be missed. In order to handle - * these signals delayed work is canceled and work task - * re-scheduled for immediate execution. It allows to handle - * missed signals, if any. In other case work handler just - * validates that no new signals have been received during - * masking. - */ - cancel_delayed_work(&priv->dwork_irq); - schedule_delayed_work(&priv->dwork_irq, 0); + /* + * It is possible, that some signals have been inserted, while + * interrupt has been masked by mlxreg_hotplug_work_handler. In this + * case such signals will be missed. In order to handle these signals + * delayed work is canceled and work task re-scheduled for immediate + * execution. It allows to handle missed signals, if any. In other case + * work handler just validates that no new signals have been received + * during masking. + */ + cancel_delayed_work(&priv->dwork_irq); + schedule_delayed_work(&priv->dwork_irq, 0); - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&priv->lock, flags); - return; - } + return; +unmask_event: + priv->not_asserted++; /* Unmask aggregation event (no need acknowledge). */ ret = regmap_write(priv->regmap, pdata->cell + MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask); diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 1be71f956d5c..8952173dd380 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -129,6 +129,7 @@ static const struct key_entry acer_wmi_keymap[] __initconst = { {KE_IGNORE, 0x83, {KEY_TOUCHPAD_TOGGLE} }, {KE_KEY, 0x85, {KEY_TOUCHPAD_TOGGLE} }, {KE_KEY, 0x86, {KEY_WLAN} }, + {KE_KEY, 0x87, {KEY_POWER} }, {KE_END, 0} }; diff --git a/drivers/platform/x86/alienware-wmi.c b/drivers/platform/x86/alienware-wmi.c index 9d7dbd925065..d975462a4c57 100644 --- a/drivers/platform/x86/alienware-wmi.c +++ b/drivers/platform/x86/alienware-wmi.c @@ -458,19 +458,19 @@ static int alienware_zone_init(struct platform_device *dev) * - zone_data num_zones is for the distinct zones */ zone_dev_attrs = - kzalloc(sizeof(struct device_attribute) * (quirks->num_zones + 1), + kcalloc(quirks->num_zones + 1, sizeof(struct device_attribute), GFP_KERNEL); if (!zone_dev_attrs) return -ENOMEM; zone_attrs = - kzalloc(sizeof(struct attribute *) * (quirks->num_zones + 2), + kcalloc(quirks->num_zones + 2, sizeof(struct attribute *), GFP_KERNEL); if (!zone_attrs) return -ENOMEM; zone_data = - kzalloc(sizeof(struct platform_zone) * (quirks->num_zones), + kcalloc(quirks->num_zones, sizeof(struct platform_zone), GFP_KERNEL); if (!zone_data) return -ENOMEM; diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c index 7c4eb86c851e..fd2ffebc868f 100644 --- a/drivers/platform/x86/apple-gmux.c +++ b/drivers/platform/x86/apple-gmux.c @@ -495,7 +495,7 @@ static int gmux_set_power_state(enum vga_switcheroo_client_id id, return gmux_set_discrete_state(apple_gmux_data, state); } -static int gmux_get_client_id(struct pci_dev *pdev) +static enum vga_switcheroo_client_id gmux_get_client_id(struct pci_dev *pdev) { /* * Early Macbook Pros with switchable graphics use nvidia diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index c4768be24ba9..700c48ddfa7c 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -1593,8 +1593,7 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj, int idx) { struct device *dev = container_of(kobj, struct device, kobj); - struct platform_device *pdev = to_platform_device(dev); - struct asus_laptop *asus = platform_get_drvdata(pdev); + struct asus_laptop *asus = dev_get_drvdata(dev); acpi_handle handle = asus->handle; bool supported; diff --git a/drivers/platform/x86/asus-wireless.c b/drivers/platform/x86/asus-wireless.c index f086469ea740..6afd011de9e5 100644 --- a/drivers/platform/x86/asus-wireless.c +++ b/drivers/platform/x86/asus-wireless.c @@ -72,7 +72,7 @@ static u64 asus_wireless_method(acpi_handle handle, const char *method, acpi_handle_err(handle, "Failed to eval method %s, param %#x (%d)\n", method, param, s); - acpi_handle_debug(handle, "%s returned %#x\n", method, (uint) ret); + acpi_handle_debug(handle, "%s returned %#llx\n", method, ret); return ret; } diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index ffffb9909ae1..3d523ca64694 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -1875,8 +1875,7 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj, struct attribute *attr, int idx) { struct device *dev = container_of(kobj, struct device, kobj); - struct platform_device *pdev = to_platform_device(dev); - struct asus_wmi *asus = platform_get_drvdata(pdev); + struct asus_wmi *asus = dev_get_drvdata(dev); bool ok = true; int devid = -1; diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index c52c6723374b..f1fa8612db40 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -38,6 +38,7 @@ struct quirk_entry { bool touchpad_led; bool kbd_led_levels_off_1; + bool kbd_missing_ac_tag; bool needs_kbd_timeouts; /* @@ -68,6 +69,10 @@ static struct quirk_entry quirk_dell_xps13_9333 = { .kbd_timeouts = { 0, 5, 15, 60, 5 * 60, 15 * 60, -1 }, }; +static struct quirk_entry quirk_dell_xps13_9370 = { + .kbd_missing_ac_tag = true, +}; + static struct quirk_entry quirk_dell_latitude_e6410 = { .kbd_led_levels_off_1 = true, }; @@ -293,6 +298,15 @@ static const struct dmi_system_id dell_quirks[] __initconst = { }, { .callback = dmi_matched, + .ident = "Dell XPS 13 9370", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "XPS 13 9370"), + }, + .driver_data = &quirk_dell_xps13_9370, + }, + { + .callback = dmi_matched, .ident = "Dell Latitude E6410", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), @@ -1401,7 +1415,8 @@ static inline int kbd_init_info(void) * timeout value which is shared for both battery and AC power * settings. So do not try to set AC values on old models. */ - if (dell_smbios_find_token(KBD_LED_AC_TOKEN)) + if ((quirks && quirks->kbd_missing_ac_tag) || + dell_smbios_find_token(KBD_LED_AC_TOKEN)) kbd_timeout_ac_supported = true; kbd_get_state(&state); diff --git a/drivers/platform/x86/dell-smbios-base.c b/drivers/platform/x86/dell-smbios-base.c index 33fb2a20458a..9dc282ed5a9e 100644 --- a/drivers/platform/x86/dell-smbios-base.c +++ b/drivers/platform/x86/dell-smbios-base.c @@ -555,11 +555,10 @@ static void free_group(struct platform_device *pdev) static int __init dell_smbios_init(void) { - const struct dmi_device *valid; int ret, wmi, smm; - valid = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, "Dell System", NULL); - if (!valid) { + if (!dmi_find_device(DMI_DEV_TYPE_OEM_STRING, "Dell System", NULL) && + !dmi_find_device(DMI_DEV_TYPE_OEM_STRING, "www.dell.com", NULL)) { pr_err("Unable to run on non-Dell system\n"); return -ENODEV; } diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index 8d102195a392..16c7f3d9a335 100644 --- a/drivers/platform/x86/dell-wmi.c +++ b/drivers/platform/x86/dell-wmi.c @@ -233,7 +233,7 @@ static const u16 bios_to_linux_keycode[256] = { [18] = KEY_PROG1, [19] = KEY_BRIGHTNESSDOWN, [20] = KEY_BRIGHTNESSUP, - [21] = KEY_UNKNOWN, + [21] = KEY_BRIGHTNESS_AUTO, [22] = KEY_KBDILLUMTOGGLE, [23] = KEY_UNKNOWN, [24] = KEY_SWITCHVIDEOMODE, @@ -261,6 +261,12 @@ static const u16 bios_to_linux_keycode[256] = { * override them. */ static const struct key_entry dell_wmi_keymap_type_0010[] = { + /* Fn-lock switched to function keys */ + { KE_IGNORE, 0x0, { KEY_RESERVED } }, + + /* Fn-lock switched to multimedia keys */ + { KE_IGNORE, 0x1, { KEY_RESERVED } }, + /* Mic mute */ { KE_KEY, 0x150, { KEY_MICMUTE } }, @@ -296,6 +302,14 @@ static const struct key_entry dell_wmi_keymap_type_0010[] = { { KE_KEY, 0x851, { KEY_PROG2 } }, { KE_KEY, 0x852, { KEY_PROG3 } }, + /* + * Radio disable (notify only -- there is no model for which the + * WMI event is supposed to trigger an action). + */ + { KE_IGNORE, 0xe008, { KEY_RFKILL } }, + + /* Fn-lock */ + { KE_IGNORE, 0xe035, { KEY_RESERVED } }, }; /* diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index cd95b6f3a064..6afeaece2f50 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -91,6 +91,9 @@ #define FLAG_RFKILL BIT(5) #define FLAG_LID BIT(8) #define FLAG_DOCK BIT(9) +#define FLAG_TOUCHPAD_TOGGLE BIT(26) +#define FLAG_MICMUTE BIT(29) +#define FLAG_SOFTKEYS (FLAG_RFKILL | FLAG_TOUCHPAD_TOGGLE | FLAG_MICMUTE) /* FUNC interface - LED control */ #define FUNC_LED_OFF BIT(0) @@ -456,14 +459,15 @@ static void acpi_fujitsu_bl_notify(struct acpi_device *device, u32 event) /* ACPI device for hotkey handling */ static const struct key_entry keymap_default[] = { - { KE_KEY, KEY1_CODE, { KEY_PROG1 } }, - { KE_KEY, KEY2_CODE, { KEY_PROG2 } }, - { KE_KEY, KEY3_CODE, { KEY_PROG3 } }, - { KE_KEY, KEY4_CODE, { KEY_PROG4 } }, - { KE_KEY, KEY5_CODE, { KEY_RFKILL } }, - { KE_KEY, BIT(5), { KEY_RFKILL } }, - { KE_KEY, BIT(26), { KEY_TOUCHPAD_TOGGLE } }, - { KE_KEY, BIT(29), { KEY_MICMUTE } }, + { KE_KEY, KEY1_CODE, { KEY_PROG1 } }, + { KE_KEY, KEY2_CODE, { KEY_PROG2 } }, + { KE_KEY, KEY3_CODE, { KEY_PROG3 } }, + { KE_KEY, KEY4_CODE, { KEY_PROG4 } }, + { KE_KEY, KEY5_CODE, { KEY_RFKILL } }, + /* Soft keys read from status flags */ + { KE_KEY, FLAG_RFKILL, { KEY_RFKILL } }, + { KE_KEY, FLAG_TOUCHPAD_TOGGLE, { KEY_TOUCHPAD_TOGGLE } }, + { KE_KEY, FLAG_MICMUTE, { KEY_MICMUTE } }, { KE_END, 0 } }; @@ -903,7 +907,8 @@ static void acpi_fujitsu_laptop_release(struct acpi_device *device) static void acpi_fujitsu_laptop_notify(struct acpi_device *device, u32 event) { struct fujitsu_laptop *priv = acpi_driver_data(device); - int scancode, i = 0, ret; + unsigned long flags; + int scancode, i = 0; unsigned int irb; if (event != ACPI_FUJITSU_NOTIFY_CODE) { @@ -930,21 +935,17 @@ static void acpi_fujitsu_laptop_notify(struct acpi_device *device, u32 event) "Unknown GIRB result [%x]\n", irb); } - /* On some models (first seen on the Skylake-based Lifebook - * E736/E746/E756), the touchpad toggle hotkey (Fn+F4) is - * handled in software; its state is queried using FUNC_FLAGS + /* + * First seen on the Skylake-based Lifebook E736/E746/E756), the + * touchpad toggle hotkey (Fn+F4) is handled in software. Other models + * have since added additional "soft keys". These are reported in the + * status flags queried using FUNC_FLAGS. */ - if (priv->flags_supported & (BIT(5) | BIT(26) | BIT(29))) { - ret = call_fext_func(device, FUNC_FLAGS, 0x1, 0x0, 0x0); - if (ret & BIT(5)) - sparse_keymap_report_event(priv->input, - BIT(5), 1, true); - if (ret & BIT(26)) - sparse_keymap_report_event(priv->input, - BIT(26), 1, true); - if (ret & BIT(29)) - sparse_keymap_report_event(priv->input, - BIT(29), 1, true); + if (priv->flags_supported & (FLAG_SOFTKEYS)) { + flags = call_fext_func(device, FUNC_FLAGS, 0x1, 0x0, 0x0); + flags &= (FLAG_SOFTKEYS); + for_each_set_bit(i, &flags, BITS_PER_LONG) + sparse_keymap_report_event(priv->input, BIT(i), 1, true); } } diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 535199c9e6bc..45b7cb01f410 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -43,6 +43,7 @@ #define IDEAPAD_RFKILL_DEV_NUM (3) #define BM_CONSERVATION_BIT (5) +#define HA_FNLOCK_BIT (10) #define CFG_BT_BIT (16) #define CFG_3G_BIT (17) @@ -59,6 +60,8 @@ static const char *const ideapad_wmi_fnesc_events[] = { enum { BMCMD_CONSERVATION_ON = 3, BMCMD_CONSERVATION_OFF = 5, + HACMD_FNLOCK_ON = 0xe, + HACMD_FNLOCK_OFF = 0xf, }; enum { @@ -139,11 +142,11 @@ static int method_gbmd(acpi_handle handle, unsigned long *ret) return result; } -static int method_sbmc(acpi_handle handle, int cmd) +static int method_int1(acpi_handle handle, char *method, int cmd) { acpi_status status; - status = acpi_execute_simple_method(handle, "SBMC", cmd); + status = acpi_execute_simple_method(handle, method, cmd); return ACPI_FAILURE(status) ? -1 : 0; } @@ -487,7 +490,7 @@ static ssize_t conservation_mode_store(struct device *dev, if (ret) return ret; - ret = method_sbmc(priv->adev->handle, state ? + ret = method_int1(priv->adev->handle, "SBMC", state ? BMCMD_CONSERVATION_ON : BMCMD_CONSERVATION_OFF); if (ret < 0) @@ -497,11 +500,51 @@ static ssize_t conservation_mode_store(struct device *dev, static DEVICE_ATTR_RW(conservation_mode); +static ssize_t fn_lock_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ideapad_private *priv = dev_get_drvdata(dev); + unsigned long result; + int hals; + int fail = read_method_int(priv->adev->handle, "HALS", &hals); + + if (fail) + return sprintf(buf, "-1\n"); + + result = hals; + return sprintf(buf, "%u\n", test_bit(HA_FNLOCK_BIT, &result)); +} + +static ssize_t fn_lock_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ideapad_private *priv = dev_get_drvdata(dev); + bool state; + int ret; + + ret = kstrtobool(buf, &state); + if (ret) + return ret; + + ret = method_int1(priv->adev->handle, "SALS", state ? + HACMD_FNLOCK_ON : + HACMD_FNLOCK_OFF); + if (ret < 0) + return -EIO; + return count; +} + +static DEVICE_ATTR_RW(fn_lock); + + static struct attribute *ideapad_attributes[] = { &dev_attr_camera_power.attr, &dev_attr_fan_mode.attr, &dev_attr_touchpad.attr, &dev_attr_conservation_mode.attr, + &dev_attr_fn_lock.attr, NULL }; @@ -522,6 +565,9 @@ static umode_t ideapad_is_visible(struct kobject *kobj, } else if (attr == &dev_attr_conservation_mode.attr) { supported = acpi_has_method(priv->adev->handle, "GBMD") && acpi_has_method(priv->adev->handle, "SBMC"); + } else if (attr == &dev_attr_fn_lock.attr) { + supported = acpi_has_method(priv->adev->handle, "HALS") && + acpi_has_method(priv->adev->handle, "SALS"); } else supported = true; @@ -1080,6 +1126,13 @@ static const struct dmi_system_id no_hw_rfkill_list[] = { }, }, { + .ident = "Lenovo ideapad MIIX 720-12IKB", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "MIIX 720-12IKB"), + }, + }, + { .ident = "Lenovo Legion Y520-15IKBN", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), @@ -1163,6 +1216,13 @@ static const struct dmi_system_id no_hw_rfkill_list[] = { DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 920-13IKB"), }, }, + { + .ident = "Lenovo Zhaoyang E42-80", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ZHAOYANG E42-80"), + }, + }, {} }; diff --git a/drivers/platform/x86/intel_ips.c b/drivers/platform/x86/intel_ips.c index a0c95853fd3f..014fc1634a3d 100644 --- a/drivers/platform/x86/intel_ips.c +++ b/drivers/platform/x86/intel_ips.c @@ -964,12 +964,12 @@ static int ips_monitor(void *data) u16 *mcp_samples, *ctv1_samples, *ctv2_samples, *mch_samples; u8 cur_seqno, last_seqno; - mcp_samples = kzalloc(sizeof(u16) * IPS_SAMPLE_COUNT, GFP_KERNEL); - ctv1_samples = kzalloc(sizeof(u16) * IPS_SAMPLE_COUNT, GFP_KERNEL); - ctv2_samples = kzalloc(sizeof(u16) * IPS_SAMPLE_COUNT, GFP_KERNEL); - mch_samples = kzalloc(sizeof(u16) * IPS_SAMPLE_COUNT, GFP_KERNEL); - cpu_samples = kzalloc(sizeof(u32) * IPS_SAMPLE_COUNT, GFP_KERNEL); - mchp_samples = kzalloc(sizeof(u32) * IPS_SAMPLE_COUNT, GFP_KERNEL); + mcp_samples = kcalloc(IPS_SAMPLE_COUNT, sizeof(u16), GFP_KERNEL); + ctv1_samples = kcalloc(IPS_SAMPLE_COUNT, sizeof(u16), GFP_KERNEL); + ctv2_samples = kcalloc(IPS_SAMPLE_COUNT, sizeof(u16), GFP_KERNEL); + mch_samples = kcalloc(IPS_SAMPLE_COUNT, sizeof(u16), GFP_KERNEL); + cpu_samples = kcalloc(IPS_SAMPLE_COUNT, sizeof(u32), GFP_KERNEL); + mchp_samples = kcalloc(IPS_SAMPLE_COUNT, sizeof(u32), GFP_KERNEL); if (!mcp_samples || !ctv1_samples || !ctv2_samples || !mch_samples || !cpu_samples || !mchp_samples) { dev_err(ips->dev, diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index 2c85f75e32b0..75c8fef7a482 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c @@ -584,11 +584,11 @@ int intel_scu_ipc_i2c_cntrl(u32 addr, u32 *data) if (cmd == IPC_I2C_READ) { writel(addr, scu->i2c_base + IPC_I2C_CNTRL_ADDR); /* Write not getting updated without delay */ - mdelay(1); + usleep_range(1000, 2000); *data = readl(scu->i2c_base + I2C_DATA_ADDR); } else if (cmd == IPC_I2C_WRITE) { writel(*data, scu->i2c_base + I2C_DATA_ADDR); - mdelay(1); + usleep_range(1000, 2000); writel(addr, scu->i2c_base + IPC_I2C_CNTRL_ADDR); } else { dev_err(scu->dev, diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index 7a0bd24c1ae2..a0fd9aa6d932 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -47,6 +47,11 @@ /* LPC bus IO offsets */ #define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR 0x2000 #define MLXPLAT_CPLD_LPC_REG_BASE_ADRR 0x2500 +#define MLXPLAT_CPLD_LPC_REG_LED1_OFFSET 0x20 +#define MLXPLAT_CPLD_LPC_REG_LED2_OFFSET 0x21 +#define MLXPLAT_CPLD_LPC_REG_LED3_OFFSET 0x22 +#define MLXPLAT_CPLD_LPC_REG_LED4_OFFSET 0x23 +#define MLXPLAT_CPLD_LPC_REG_LED5_OFFSET 0x24 #define MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET 0x3a #define MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET 0x3b #define MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET 0x40 @@ -84,6 +89,8 @@ #define MLXPLAT_CPLD_PWR_MASK GENMASK(1, 0) #define MLXPLAT_CPLD_FAN_MASK GENMASK(3, 0) #define MLXPLAT_CPLD_FAN_NG_MASK GENMASK(5, 0) +#define MLXPLAT_CPLD_LED_LO_NIBBLE_MASK GENMASK(7, 4) +#define MLXPLAT_CPLD_LED_HI_NIBBLE_MASK GENMASK(3, 0) /* Default I2C parent bus number */ #define MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR 1 @@ -114,11 +121,13 @@ * @pdev_i2c - i2c controller platform device * @pdev_mux - array of mux platform devices * @pdev_hotplug - hotplug platform devices + * @pdev_led - led platform devices */ struct mlxplat_priv { struct platform_device *pdev_i2c; struct platform_device *pdev_mux[MLXPLAT_CPLD_LPC_MUX_DEVS]; struct platform_device *pdev_hotplug; + struct platform_device *pdev_led; }; /* Regions for LPC I2C controller and LPC base register space */ @@ -592,9 +601,227 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_ng_data = { .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, }; +/* Platform led default data */ +static struct mlxreg_core_data mlxplat_mlxcpld_default_led_data[] = { + { + .label = "status:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "status:red", + .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK + }, + { + .label = "psu:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, + { + .label = "psu:red", + .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, + { + .label = "fan1:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "fan1:red", + .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "fan2:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, + { + .label = "fan2:red", + .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, + { + .label = "fan3:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "fan3:red", + .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "fan4:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, + { + .label = "fan4:red", + .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, +}; + +static struct mlxreg_core_platform_data mlxplat_default_led_data = { + .data = mlxplat_mlxcpld_default_led_data, + .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_led_data), +}; + +/* Platform led MSN21xx system family data */ +static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_led_data[] = { + { + .label = "status:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "status:red", + .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK + }, + { + .label = "fan:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "fan:red", + .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "psu1:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "psu1:red", + .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "psu2:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, + { + .label = "psu2:red", + .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, + { + .label = "uid:blue", + .reg = MLXPLAT_CPLD_LPC_REG_LED5_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, +}; + +static struct mlxreg_core_platform_data mlxplat_msn21xx_led_data = { + .data = mlxplat_mlxcpld_msn21xx_led_data, + .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_led_data), +}; + +/* Platform led for default data for 200GbE systems */ +static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_led_data[] = { + { + .label = "status:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "status:orange", + .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK + }, + { + .label = "psu:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, + { + .label = "psu:orange", + .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, + { + .label = "fan1:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "fan1:orange", + .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "fan2:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, + { + .label = "fan2:orange", + .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, + { + .label = "fan3:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "fan3:orange", + .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "fan4:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, + { + .label = "fan4:orange", + .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, + { + .label = "fan5:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "fan5:orange", + .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "fan6:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, + { + .label = "fan6:orange", + .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, +}; + +static struct mlxreg_core_platform_data mlxplat_default_ng_led_data = { + .data = mlxplat_mlxcpld_default_ng_led_data, + .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_led_data), +}; + + static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) { switch (reg) { + case MLXPLAT_CPLD_LPC_REG_LED1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LED2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET: @@ -611,6 +838,11 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) { switch (reg) { + case MLXPLAT_CPLD_LPC_REG_LED1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LED2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET: @@ -632,6 +864,11 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { + case MLXPLAT_CPLD_LPC_REG_LED1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LED2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET: @@ -692,6 +929,7 @@ static struct resource mlxplat_mlxcpld_resources[] = { static struct platform_device *mlxplat_dev; static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug; +static struct mlxreg_core_platform_data *mlxplat_led; static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) { @@ -705,6 +943,7 @@ static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) mlxplat_hotplug = &mlxplat_mlxcpld_default_data; mlxplat_hotplug->deferred_nr = mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; + mlxplat_led = &mlxplat_default_led_data; return 1; }; @@ -721,6 +960,7 @@ static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi) mlxplat_hotplug = &mlxplat_mlxcpld_msn21xx_data; mlxplat_hotplug->deferred_nr = mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; + mlxplat_led = &mlxplat_msn21xx_led_data; return 1; }; @@ -737,6 +977,7 @@ static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi) mlxplat_hotplug = &mlxplat_mlxcpld_msn274x_data; mlxplat_hotplug->deferred_nr = mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; + mlxplat_led = &mlxplat_default_led_data; return 1; }; @@ -753,6 +994,7 @@ static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi) mlxplat_hotplug = &mlxplat_mlxcpld_msn201x_data; mlxplat_hotplug->deferred_nr = mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; + mlxplat_led = &mlxplat_default_ng_led_data; return 1; }; @@ -769,6 +1011,7 @@ static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi) mlxplat_hotplug = &mlxplat_mlxcpld_default_ng_data; mlxplat_hotplug->deferred_nr = mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; + mlxplat_led = &mlxplat_msn21xx_led_data; return 1; }; @@ -844,6 +1087,36 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { DMI_MATCH(DMI_PRODUCT_NAME, "SN34"), }, }, + { + .callback = mlxplat_dmi_default_matched, + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "VMOD0001"), + }, + }, + { + .callback = mlxplat_dmi_msn21xx_matched, + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "VMOD0002"), + }, + }, + { + .callback = mlxplat_dmi_msn274x_matched, + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "VMOD0003"), + }, + }, + { + .callback = mlxplat_dmi_msn201x_matched, + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "VMOD0004"), + }, + }, + { + .callback = mlxplat_dmi_qmb7xx_matched, + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "VMOD0005"), + }, + }, { } }; @@ -960,14 +1233,27 @@ static int __init mlxplat_init(void) goto fail_platform_mux_register; } + /* Add LED driver. */ + mlxplat_led->regmap = mlxplat_hotplug->regmap; + priv->pdev_led = platform_device_register_resndata( + &mlxplat_dev->dev, "leds-mlxreg", + PLATFORM_DEVID_NONE, NULL, 0, + mlxplat_led, sizeof(*mlxplat_led)); + if (IS_ERR(priv->pdev_led)) { + err = PTR_ERR(priv->pdev_led); + goto fail_platform_hotplug_register; + } + /* Sync registers with hardware. */ regcache_mark_dirty(mlxplat_hotplug->regmap); err = regcache_sync(mlxplat_hotplug->regmap); if (err) - goto fail_platform_hotplug_register; + goto fail_platform_led_register; return 0; +fail_platform_led_register: + platform_device_unregister(priv->pdev_led); fail_platform_hotplug_register: platform_device_unregister(priv->pdev_hotplug); fail_platform_mux_register: @@ -986,6 +1272,7 @@ static void __exit mlxplat_exit(void) struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev); int i; + platform_device_unregister(priv->pdev_led); platform_device_unregister(priv->pdev_hotplug); for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--) diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c index 5c39b3211709..8361ad75389a 100644 --- a/drivers/platform/x86/panasonic-laptop.c +++ b/drivers/platform/x86/panasonic-laptop.c @@ -571,7 +571,7 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device) return -ENOMEM; } - pcc->sinf = kzalloc(sizeof(u32) * (num_sifr + 1), GFP_KERNEL); + pcc->sinf = kcalloc(num_sifr + 1, sizeof(u32), GFP_KERNEL); if (!pcc->sinf) { result = -ENOMEM; goto out_hotkey; diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index 03305e0b89ff..7b160ee98115 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c @@ -1216,8 +1216,7 @@ static umode_t samsung_sysfs_is_visible(struct kobject *kobj, struct attribute *attr, int idx) { struct device *dev = container_of(kobj, struct device, kobj); - struct platform_device *pdev = to_platform_device(dev); - struct samsung_laptop *samsung = platform_get_drvdata(pdev); + struct samsung_laptop *samsung = dev_get_drvdata(dev); bool ok = true; if (attr == &dev_attr_performance_level.attr) diff --git a/drivers/platform/x86/silead_dmi.c b/drivers/platform/x86/silead_dmi.c index 452aacabaa8e..853a7ce4601c 100644 --- a/drivers/platform/x86/silead_dmi.c +++ b/drivers/platform/x86/silead_dmi.c @@ -53,6 +53,20 @@ static const struct silead_ts_dmi_data jumper_ezpad_mini3_data = { .properties = jumper_ezpad_mini3_props, }; +static const struct property_entry jumper_ezpad_6_pro_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1980), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1500), + PROPERTY_ENTRY_STRING("firmware-name", "gsl3692-jumper-ezpad-6-pro.fw"), + PROPERTY_ENTRY_U32("silead,max-fingers", 10), + PROPERTY_ENTRY_BOOL("silead,home-button"), + { } +}; + +static const struct silead_ts_dmi_data jumper_ezpad_6_pro_data = { + .acpi_name = "MSSL1680:00", + .properties = jumper_ezpad_6_pro_props, +}; + static const struct property_entry dexp_ursus_7w_props[] = { PROPERTY_ENTRY_U32("touchscreen-size-x", 890), PROPERTY_ENTRY_U32("touchscreen-size-y", 630), @@ -127,7 +141,25 @@ static const struct silead_ts_dmi_data pipo_w2s_data = { .properties = pipo_w2s_props, }; -static const struct property_entry pov_mobii_wintab_p800w_props[] = { +static const struct property_entry pov_mobii_wintab_p800w_v20_props[] = { + PROPERTY_ENTRY_U32("touchscreen-min-x", 32), + PROPERTY_ENTRY_U32("touchscreen-min-y", 16), + PROPERTY_ENTRY_U32("touchscreen-size-x", 1692), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1146), + PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), + PROPERTY_ENTRY_STRING("firmware-name", + "gsl3680-pov-mobii-wintab-p800w-v20.fw"), + PROPERTY_ENTRY_U32("silead,max-fingers", 10), + PROPERTY_ENTRY_BOOL("silead,home-button"), + { } +}; + +static const struct silead_ts_dmi_data pov_mobii_wintab_p800w_v20_data = { + .acpi_name = "MSSL1680:00", + .properties = pov_mobii_wintab_p800w_v20_props, +}; + +static const struct property_entry pov_mobii_wintab_p800w_v21_props[] = { PROPERTY_ENTRY_U32("touchscreen-size-x", 1800), PROPERTY_ENTRY_U32("touchscreen-size-y", 1150), PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), @@ -137,9 +169,9 @@ static const struct property_entry pov_mobii_wintab_p800w_props[] = { { } }; -static const struct silead_ts_dmi_data pov_mobii_wintab_p800w_data = { +static const struct silead_ts_dmi_data pov_mobii_wintab_p800w_v21_data = { .acpi_name = "MSSL1680:00", - .properties = pov_mobii_wintab_p800w_props, + .properties = pov_mobii_wintab_p800w_v21_props, }; static const struct property_entry itworks_tw891_props[] = { @@ -277,6 +309,23 @@ static const struct silead_ts_dmi_data teclast_x3_plus_data = { .properties = teclast_x3_plus_props, }; +static const struct property_entry onda_v891w_v1_props[] = { + PROPERTY_ENTRY_U32("touchscreen-min-x", 46), + PROPERTY_ENTRY_U32("touchscreen-min-y", 8), + PROPERTY_ENTRY_U32("touchscreen-size-x", 1676), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1130), + PROPERTY_ENTRY_STRING("firmware-name", + "gsl3680-onda-v891w-v1.fw"), + PROPERTY_ENTRY_U32("silead,max-fingers", 10), + PROPERTY_ENTRY_BOOL("silead,home-button"), + { } +}; + +static const struct silead_ts_dmi_data onda_v891w_v1_data = { + .acpi_name = "MSSL1680:00", + .properties = onda_v891w_v1_props, +}; + static const struct dmi_system_id silead_ts_dmi_table[] = { { /* CUBE iwork8 Air */ @@ -297,6 +346,17 @@ static const struct dmi_system_id silead_ts_dmi_table[] = { }, }, { + /* Jumper EZpad 6 Pro */ + .driver_data = (void *)&jumper_ezpad_6_pro_data, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Jumper"), + DMI_MATCH(DMI_PRODUCT_NAME, "EZpad"), + DMI_MATCH(DMI_BIOS_VERSION, "5.12"), + /* Above matches are too generic, add bios-date match */ + DMI_MATCH(DMI_BIOS_DATE, "08/18/2017"), + }, + }, + { /* DEXP Ursus 7W */ .driver_data = (void *)&dexp_ursus_7w_data, .matches = { @@ -361,8 +421,19 @@ static const struct dmi_system_id silead_ts_dmi_table[] = { }, }, { - /* Point of View mobii wintab p800w */ - .driver_data = (void *)&pov_mobii_wintab_p800w_data, + /* Point of View mobii wintab p800w (v2.0) */ + .driver_data = (void *)&pov_mobii_wintab_p800w_v20_data, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), + DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"), + DMI_MATCH(DMI_BIOS_VERSION, "3BAIR1014"), + /* Above matches are too generic, add bios-date match */ + DMI_MATCH(DMI_BIOS_DATE, "10/24/2014"), + }, + }, + { + /* Point of View mobii wintab p800w (v2.1) */ + .driver_data = (void *)&pov_mobii_wintab_p800w_v21_data, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"), @@ -413,6 +484,15 @@ static const struct dmi_system_id silead_ts_dmi_table[] = { }, }, { + /* Chuwi Hi8 (H1D_S806_206) */ + .driver_data = (void *)&chuwi_hi8_data, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), + DMI_MATCH(DMI_PRODUCT_NAME, "BayTrail"), + DMI_MATCH(DMI_BIOS_VERSION, "H1D_S806_206"), + }, + }, + { /* Chuwi Vi8 (CWI506) */ .driver_data = (void *)&chuwi_vi8_data, .matches = { @@ -463,6 +543,17 @@ static const struct dmi_system_id silead_ts_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Y8W81"), }, }, + { + /* ONDA V891w revision P891WBEBV1B00 aka v1 */ + .driver_data = (void *)&onda_v891w_v1_data, + .matches = { + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "ONDA"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONDA Tablet"), + DMI_EXACT_MATCH(DMI_BOARD_VERSION, "V001"), + /* Exact match, different versions need different fw */ + DMI_EXACT_MATCH(DMI_BIOS_VERSION, "ONDA.W89EBBN08"), + }, + }, { }, }; diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index da1ca4856ea1..cae9b0595692 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -212,7 +212,12 @@ enum tpacpi_hkey_event_t { TP_HKEY_EV_ALARM_BAT_XHOT = 0x6012, /* battery critically hot */ TP_HKEY_EV_ALARM_SENSOR_HOT = 0x6021, /* sensor too hot */ TP_HKEY_EV_ALARM_SENSOR_XHOT = 0x6022, /* sensor critically hot */ - TP_HKEY_EV_THM_TABLE_CHANGED = 0x6030, /* thermal table changed */ + TP_HKEY_EV_THM_TABLE_CHANGED = 0x6030, /* windows; thermal table changed */ + TP_HKEY_EV_THM_CSM_COMPLETED = 0x6032, /* windows; thermal control set + * command completed. Related to + * AML DYTC */ + TP_HKEY_EV_THM_TRANSFM_CHANGED = 0x60F0, /* windows; thermal transformation + * changed. Related to AML GMTS */ /* AC-related events */ TP_HKEY_EV_AC_CHANGED = 0x6040, /* AC status changed */ @@ -4034,15 +4039,23 @@ static bool hotkey_notify_6xxx(const u32 hkey, bool *send_acpi_ev, bool *ignore_acpi_ev) { - bool known = true; - /* 0x6000-0x6FFF: thermal alarms/notices and keyboard events */ *send_acpi_ev = true; *ignore_acpi_ev = false; switch (hkey) { case TP_HKEY_EV_THM_TABLE_CHANGED: - pr_info("EC reports that Thermal Table has changed\n"); + pr_debug("EC reports: Thermal Table has changed\n"); + /* recommended action: do nothing, we don't have + * Lenovo ATM information */ + return true; + case TP_HKEY_EV_THM_CSM_COMPLETED: + pr_debug("EC reports: Thermal Control Command set completed (DYTC)\n"); + /* recommended action: do nothing, we don't have + * Lenovo ATM information */ + return true; + case TP_HKEY_EV_THM_TRANSFM_CHANGED: + pr_debug("EC reports: Thermal Transformation changed (GMTS)\n"); /* recommended action: do nothing, we don't have * Lenovo ATM information */ return true; @@ -4083,7 +4096,7 @@ static bool hotkey_notify_6xxx(const u32 hkey, tpacpi_input_send_tabletsw(); hotkey_tablet_mode_notify_change(); *send_acpi_ev = false; - break; + return true; case TP_HKEY_EV_PALM_DETECTED: case TP_HKEY_EV_PALM_UNDETECTED: @@ -4092,13 +4105,12 @@ static bool hotkey_notify_6xxx(const u32 hkey, return true; default: - pr_warn("unknown possible thermal alarm or keyboard event received\n"); - known = false; + /* report simply as unknown, no sensor dump */ + return false; } thermal_dump_all_sensors(); - - return known; + return true; } static void hotkey_notify(struct ibm_struct *ibm, u32 event) @@ -6006,7 +6018,7 @@ static int __init led_init(struct ibm_init_struct *iibm) if (led_supported == TPACPI_LED_NONE) return 1; - tpacpi_leds = kzalloc(sizeof(*tpacpi_leds) * TPACPI_LED_NUMLEDS, + tpacpi_leds = kcalloc(TPACPI_LED_NUMLEDS, sizeof(*tpacpi_leds), GFP_KERNEL); if (!tpacpi_leds) { pr_err("Out of memory for LED data\n"); diff --git a/drivers/power/supply/charger-manager.c b/drivers/power/supply/charger-manager.c index 2a50b4654793..faa1a67cf3d2 100644 --- a/drivers/power/supply/charger-manager.c +++ b/drivers/power/supply/charger-manager.c @@ -1380,7 +1380,7 @@ static int charger_manager_register_sysfs(struct charger_manager *cm) snprintf(buf, 10, "charger.%d", i); str = devm_kzalloc(cm->dev, - sizeof(char) * (strlen(buf) + 1), GFP_KERNEL); + strlen(buf) + 1, GFP_KERNEL); if (!str) return -ENOMEM; @@ -1522,8 +1522,10 @@ static struct charger_desc *of_cm_parse_desc(struct device *dev) of_property_read_u32(np, "cm-num-chargers", &num_chgs); if (num_chgs) { /* Allocate empty bin at the tail of array */ - desc->psy_charger_stat = devm_kzalloc(dev, sizeof(char *) - * (num_chgs + 1), GFP_KERNEL); + desc->psy_charger_stat = devm_kcalloc(dev, + num_chgs + 1, + sizeof(char *), + GFP_KERNEL); if (desc->psy_charger_stat) { int i; for (i = 0; i < num_chgs; i++) @@ -1555,8 +1557,9 @@ static struct charger_desc *of_cm_parse_desc(struct device *dev) struct charger_regulator *chg_regs; struct device_node *child; - chg_regs = devm_kzalloc(dev, sizeof(*chg_regs) - * desc->num_charger_regulators, + chg_regs = devm_kcalloc(dev, + desc->num_charger_regulators, + sizeof(*chg_regs), GFP_KERNEL); if (!chg_regs) return ERR_PTR(-ENOMEM); @@ -1573,9 +1576,10 @@ static struct charger_desc *of_cm_parse_desc(struct device *dev) /* charger cables */ chg_regs->num_cables = of_get_child_count(child); if (chg_regs->num_cables) { - cables = devm_kzalloc(dev, sizeof(*cables) - * chg_regs->num_cables, - GFP_KERNEL); + cables = devm_kcalloc(dev, + chg_regs->num_cables, + sizeof(*cables), + GFP_KERNEL); if (!cables) { of_node_put(child); return ERR_PTR(-ENOMEM); @@ -1725,10 +1729,11 @@ static int charger_manager_probe(struct platform_device *pdev) cm->charger_psy_desc.name = cm->psy_name_buf; /* Allocate for psy properties because they may vary */ - cm->charger_psy_desc.properties = devm_kzalloc(&pdev->dev, - sizeof(enum power_supply_property) - * (ARRAY_SIZE(default_charger_props) + - NUM_CHARGER_PSY_OPTIONAL), GFP_KERNEL); + cm->charger_psy_desc.properties = + devm_kcalloc(&pdev->dev, + ARRAY_SIZE(default_charger_props) + + NUM_CHARGER_PSY_OPTIONAL, + sizeof(enum power_supply_property), GFP_KERNEL); if (!cm->charger_psy_desc.properties) return -ENOMEM; diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c index f57ab0a27301..d21f478741c1 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c @@ -263,8 +263,8 @@ static int power_supply_check_supplies(struct power_supply *psy) if (!psy->supplied_from) return -ENOMEM; - *psy->supplied_from = devm_kzalloc(&psy->dev, - sizeof(char *) * (cnt - 1), + *psy->supplied_from = devm_kcalloc(&psy->dev, + cnt - 1, sizeof(char *), GFP_KERNEL); if (!*psy->supplied_from) return -ENOMEM; diff --git a/drivers/power/supply/wm97xx_battery.c b/drivers/power/supply/wm97xx_battery.c index bd4f66651513..6754e761778a 100644 --- a/drivers/power/supply/wm97xx_battery.c +++ b/drivers/power/supply/wm97xx_battery.c @@ -201,7 +201,7 @@ static int wm97xx_bat_probe(struct platform_device *dev) if (pdata->min_voltage >= 0) props++; /* POWER_SUPPLY_PROP_VOLTAGE_MIN */ - prop = kzalloc(props * sizeof(*prop), GFP_KERNEL); + prop = kcalloc(props, sizeof(*prop), GFP_KERNEL); if (!prop) { ret = -ENOMEM; goto err3; diff --git a/drivers/power/supply/z2_battery.c b/drivers/power/supply/z2_battery.c index 8a43b49cfd35..bcc2d1a9b0a7 100644 --- a/drivers/power/supply/z2_battery.c +++ b/drivers/power/supply/z2_battery.c @@ -146,7 +146,7 @@ static int z2_batt_ps_init(struct z2_charger *charger, int props) if (info->min_voltage >= 0) props++; /* POWER_SUPPLY_PROP_VOLTAGE_MIN */ - prop = kzalloc(props * sizeof(*prop), GFP_KERNEL); + prop = kcalloc(props, sizeof(*prop), GFP_KERNEL); if (!prop) return -ENOMEM; diff --git a/drivers/powercap/powercap_sys.c b/drivers/powercap/powercap_sys.c index 64b2b2501a79..9e2f274bd44f 100644 --- a/drivers/powercap/powercap_sys.c +++ b/drivers/powercap/powercap_sys.c @@ -545,15 +545,16 @@ struct powercap_zone *powercap_register_zone( dev_set_name(&power_zone->dev, "%s:%x", dev_name(power_zone->dev.parent), power_zone->id); - power_zone->constraints = kzalloc(sizeof(*power_zone->constraints) * - nr_constraints, GFP_KERNEL); + power_zone->constraints = kcalloc(nr_constraints, + sizeof(*power_zone->constraints), + GFP_KERNEL); if (!power_zone->constraints) goto err_const_alloc; nr_attrs = nr_constraints * POWERCAP_CONSTRAINTS_ATTRS + POWERCAP_ZONE_MAX_ATTRS + 1; - power_zone->zone_dev_attrs = kzalloc(sizeof(void *) * - nr_attrs, GFP_KERNEL); + power_zone->zone_dev_attrs = kcalloc(nr_attrs, sizeof(void *), + GFP_KERNEL); if (!power_zone->zone_dev_attrs) goto err_attr_alloc; create_power_zone_common_attributes(power_zone); diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 4635cb35008c..a4d262db9945 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -401,7 +401,7 @@ config PWM_STI config PWM_STM32 tristate "STMicroelectronics STM32 PWM" - depends on MFD_STM32_TIMERS || COMPILE_TEST + depends on MFD_STM32_TIMERS help Generic PWM framework driver for STM32 SoCs. diff --git a/drivers/pwm/pwm-atmel-tcb.c b/drivers/pwm/pwm-atmel-tcb.c index 4fb1be246c44..0d0f8376bc35 100644 --- a/drivers/pwm/pwm-atmel-tcb.c +++ b/drivers/pwm/pwm-atmel-tcb.c @@ -460,8 +460,7 @@ MODULE_DEVICE_TABLE(of, atmel_tcb_pwm_dt_ids); #ifdef CONFIG_PM_SLEEP static int atmel_tcb_pwm_suspend(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct atmel_tcb_pwm_chip *tcbpwm = platform_get_drvdata(pdev); + struct atmel_tcb_pwm_chip *tcbpwm = dev_get_drvdata(dev); void __iomem *base = tcbpwm->tc->regs; int i; @@ -478,8 +477,7 @@ static int atmel_tcb_pwm_suspend(struct device *dev) static int atmel_tcb_pwm_resume(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct atmel_tcb_pwm_chip *tcbpwm = platform_get_drvdata(pdev); + struct atmel_tcb_pwm_chip *tcbpwm = dev_get_drvdata(dev); void __iomem *base = tcbpwm->tc->regs; int i; diff --git a/drivers/pwm/pwm-lp3943.c b/drivers/pwm/pwm-lp3943.c index 52584e9962ed..15b40a8bc4fb 100644 --- a/drivers/pwm/pwm-lp3943.c +++ b/drivers/pwm/pwm-lp3943.c @@ -225,7 +225,7 @@ static int lp3943_pwm_parse_dt(struct device *dev, if (num_outputs == 0) continue; - output = devm_kzalloc(dev, sizeof(*output) * num_outputs, + output = devm_kcalloc(dev, num_outputs, sizeof(*output), GFP_KERNEL); if (!output) return -ENOMEM; diff --git a/drivers/pwm/pwm-lpss-platform.c b/drivers/pwm/pwm-lpss-platform.c index 5d6ed1507d29..5561b9e190f8 100644 --- a/drivers/pwm/pwm-lpss-platform.c +++ b/drivers/pwm/pwm-lpss-platform.c @@ -74,6 +74,10 @@ static int pwm_lpss_remove_platform(struct platform_device *pdev) return pwm_lpss_remove(lpwm); } +static SIMPLE_DEV_PM_OPS(pwm_lpss_platform_pm_ops, + pwm_lpss_suspend, + pwm_lpss_resume); + static const struct acpi_device_id pwm_lpss_acpi_match[] = { { "80860F09", (unsigned long)&pwm_lpss_byt_info }, { "80862288", (unsigned long)&pwm_lpss_bsw_info }, @@ -86,6 +90,7 @@ static struct platform_driver pwm_lpss_driver_platform = { .driver = { .name = "pwm-lpss", .acpi_match_table = pwm_lpss_acpi_match, + .pm = &pwm_lpss_platform_pm_ops, }, .probe = pwm_lpss_probe_platform, .remove = pwm_lpss_remove_platform, diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c index 8db0d40ccacd..4721a264bac2 100644 --- a/drivers/pwm/pwm-lpss.c +++ b/drivers/pwm/pwm-lpss.c @@ -32,10 +32,13 @@ /* Size of each PWM register space if multiple */ #define PWM_SIZE 0x400 +#define MAX_PWMS 4 + struct pwm_lpss_chip { struct pwm_chip chip; void __iomem *regs; const struct pwm_lpss_boardinfo *info; + u32 saved_ctrl[MAX_PWMS]; }; static inline struct pwm_lpss_chip *to_lpwm(struct pwm_chip *chip) @@ -177,6 +180,9 @@ struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r, unsigned long c; int ret; + if (WARN_ON(info->npwm > MAX_PWMS)) + return ERR_PTR(-ENODEV); + lpwm = devm_kzalloc(dev, sizeof(*lpwm), GFP_KERNEL); if (!lpwm) return ERR_PTR(-ENOMEM); @@ -212,6 +218,30 @@ int pwm_lpss_remove(struct pwm_lpss_chip *lpwm) } EXPORT_SYMBOL_GPL(pwm_lpss_remove); +int pwm_lpss_suspend(struct device *dev) +{ + struct pwm_lpss_chip *lpwm = dev_get_drvdata(dev); + int i; + + for (i = 0; i < lpwm->info->npwm; i++) + lpwm->saved_ctrl[i] = readl(lpwm->regs + i * PWM_SIZE + PWM); + + return 0; +} +EXPORT_SYMBOL_GPL(pwm_lpss_suspend); + +int pwm_lpss_resume(struct device *dev) +{ + struct pwm_lpss_chip *lpwm = dev_get_drvdata(dev); + int i; + + for (i = 0; i < lpwm->info->npwm; i++) + writel(lpwm->saved_ctrl[i], lpwm->regs + i * PWM_SIZE + PWM); + + return 0; +} +EXPORT_SYMBOL_GPL(pwm_lpss_resume); + MODULE_DESCRIPTION("PWM driver for Intel LPSS"); MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/pwm/pwm-lpss.h b/drivers/pwm/pwm-lpss.h index 98306bb02cfe..7a4238ad1fcb 100644 --- a/drivers/pwm/pwm-lpss.h +++ b/drivers/pwm/pwm-lpss.h @@ -28,5 +28,7 @@ struct pwm_lpss_boardinfo { struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r, const struct pwm_lpss_boardinfo *info); int pwm_lpss_remove(struct pwm_lpss_chip *lpwm); +int pwm_lpss_suspend(struct device *dev); +int pwm_lpss_resume(struct device *dev); #endif /* __PWM_LPSS_H */ diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c index 0767deba8e62..822860b4801a 100644 --- a/drivers/pwm/pwm-meson.c +++ b/drivers/pwm/pwm-meson.c @@ -541,8 +541,8 @@ static int meson_pwm_probe(struct platform_device *pdev) meson->data = of_device_get_match_data(&pdev->dev); meson->inverter_mask = BIT(meson->chip.npwm) - 1; - channels = devm_kcalloc(&pdev->dev, meson->chip.npwm, sizeof(*meson), - GFP_KERNEL); + channels = devm_kcalloc(&pdev->dev, meson->chip.npwm, + sizeof(*channels), GFP_KERNEL); if (!channels) return -ENOMEM; diff --git a/drivers/pwm/pwm-rcar.c b/drivers/pwm/pwm-rcar.c index 91d11f2e2fef..748f614d5375 100644 --- a/drivers/pwm/pwm-rcar.c +++ b/drivers/pwm/pwm-rcar.c @@ -261,8 +261,7 @@ MODULE_DEVICE_TABLE(of, rcar_pwm_of_table); #ifdef CONFIG_PM_SLEEP static struct pwm_device *rcar_pwm_dev_to_pwm_dev(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct rcar_pwm_chip *rcar_pwm = platform_get_drvdata(pdev); + struct rcar_pwm_chip *rcar_pwm = dev_get_drvdata(dev); struct pwm_chip *chip = &rcar_pwm->chip; return &chip->pwms[0]; diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c index 2708212933f7..4f842550fbd1 100644 --- a/drivers/pwm/pwm-stm32.c +++ b/drivers/pwm/pwm-stm32.c @@ -8,6 +8,7 @@ * pwm-atmel.c from Bo Shen */ +#include <linux/bitfield.h> #include <linux/mfd/stm32-timers.h> #include <linux/module.h> #include <linux/of.h> @@ -25,6 +26,7 @@ struct stm32_pwm { struct regmap *regmap; u32 max_arr; bool have_complementary_output; + u32 capture[4] ____cacheline_aligned; /* DMA'able buffer */ }; struct stm32_breakinput { @@ -62,6 +64,258 @@ static int write_ccrx(struct stm32_pwm *dev, int ch, u32 value) return -EINVAL; } +#define TIM_CCER_CC12P (TIM_CCER_CC1P | TIM_CCER_CC2P) +#define TIM_CCER_CC12E (TIM_CCER_CC1E | TIM_CCER_CC2E) +#define TIM_CCER_CC34P (TIM_CCER_CC3P | TIM_CCER_CC4P) +#define TIM_CCER_CC34E (TIM_CCER_CC3E | TIM_CCER_CC4E) + +/* + * Capture using PWM input mode: + * ___ ___ + * TI[1, 2, 3 or 4]: ........._| |________| + * ^0 ^1 ^2 + * . . . + * . . XXXXX + * . . XXXXX | + * . XXXXX . | + * XXXXX . . | + * COUNTER: ______XXXXX . . . |_XXX + * start^ . . . ^stop + * . . . . + * v v . v + * v + * CCR1/CCR3: tx..........t0...........t2 + * CCR2/CCR4: tx..............t1......... + * + * DMA burst transfer: | | + * v v + * DMA buffer: { t0, tx } { t2, t1 } + * DMA done: ^ + * + * 0: IC1/3 snapchot on rising edge: counter value -> CCR1/CCR3 + * + DMA transfer CCR[1/3] & CCR[2/4] values (t0, tx: doesn't care) + * 1: IC2/4 snapchot on falling edge: counter value -> CCR2/CCR4 + * 2: IC1/3 snapchot on rising edge: counter value -> CCR1/CCR3 + * + DMA transfer CCR[1/3] & CCR[2/4] values (t2, t1) + * + * DMA done, compute: + * - Period = t2 - t0 + * - Duty cycle = t1 - t0 + */ +static int stm32_pwm_raw_capture(struct stm32_pwm *priv, struct pwm_device *pwm, + unsigned long tmo_ms, u32 *raw_prd, + u32 *raw_dty) +{ + struct device *parent = priv->chip.dev->parent; + enum stm32_timers_dmas dma_id; + u32 ccen, ccr; + int ret; + + /* Ensure registers have been updated, enable counter and capture */ + regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG); + regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, TIM_CR1_CEN); + + /* Use cc1 or cc3 DMA resp for PWM input channels 1 & 2 or 3 & 4 */ + dma_id = pwm->hwpwm < 2 ? STM32_TIMERS_DMA_CH1 : STM32_TIMERS_DMA_CH3; + ccen = pwm->hwpwm < 2 ? TIM_CCER_CC12E : TIM_CCER_CC34E; + ccr = pwm->hwpwm < 2 ? TIM_CCR1 : TIM_CCR3; + regmap_update_bits(priv->regmap, TIM_CCER, ccen, ccen); + + /* + * Timer DMA burst mode. Request 2 registers, 2 bursts, to get both + * CCR1 & CCR2 (or CCR3 & CCR4) on each capture event. + * We'll get two capture snapchots: { CCR1, CCR2 }, { CCR1, CCR2 } + * or { CCR3, CCR4 }, { CCR3, CCR4 } + */ + ret = stm32_timers_dma_burst_read(parent, priv->capture, dma_id, ccr, 2, + 2, tmo_ms); + if (ret) + goto stop; + + /* Period: t2 - t0 (take care of counter overflow) */ + if (priv->capture[0] <= priv->capture[2]) + *raw_prd = priv->capture[2] - priv->capture[0]; + else + *raw_prd = priv->max_arr - priv->capture[0] + priv->capture[2]; + + /* Duty cycle capture requires at least two capture units */ + if (pwm->chip->npwm < 2) + *raw_dty = 0; + else if (priv->capture[0] <= priv->capture[3]) + *raw_dty = priv->capture[3] - priv->capture[0]; + else + *raw_dty = priv->max_arr - priv->capture[0] + priv->capture[3]; + + if (*raw_dty > *raw_prd) { + /* + * Race beetween PWM input and DMA: it may happen + * falling edge triggers new capture on TI2/4 before DMA + * had a chance to read CCR2/4. It means capture[1] + * contains period + duty_cycle. So, subtract period. + */ + *raw_dty -= *raw_prd; + } + +stop: + regmap_update_bits(priv->regmap, TIM_CCER, ccen, 0); + regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0); + + return ret; +} + +static int stm32_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_capture *result, unsigned long tmo_ms) +{ + struct stm32_pwm *priv = to_stm32_pwm_dev(chip); + unsigned long long prd, div, dty; + unsigned long rate; + unsigned int psc = 0, icpsc, scale; + u32 raw_prd = 0, raw_dty = 0; + int ret = 0; + + mutex_lock(&priv->lock); + + if (active_channels(priv)) { + ret = -EBUSY; + goto unlock; + } + + ret = clk_enable(priv->clk); + if (ret) { + dev_err(priv->chip.dev, "failed to enable counter clock\n"); + goto unlock; + } + + rate = clk_get_rate(priv->clk); + if (!rate) { + ret = -EINVAL; + goto clk_dis; + } + + /* prescaler: fit timeout window provided by upper layer */ + div = (unsigned long long)rate * (unsigned long long)tmo_ms; + do_div(div, MSEC_PER_SEC); + prd = div; + while ((div > priv->max_arr) && (psc < MAX_TIM_PSC)) { + psc++; + div = prd; + do_div(div, psc + 1); + } + regmap_write(priv->regmap, TIM_ARR, priv->max_arr); + regmap_write(priv->regmap, TIM_PSC, psc); + + /* Map TI1 or TI2 PWM input to IC1 & IC2 (or TI3/4 to IC3 & IC4) */ + regmap_update_bits(priv->regmap, + pwm->hwpwm < 2 ? TIM_CCMR1 : TIM_CCMR2, + TIM_CCMR_CC1S | TIM_CCMR_CC2S, pwm->hwpwm & 0x1 ? + TIM_CCMR_CC1S_TI2 | TIM_CCMR_CC2S_TI2 : + TIM_CCMR_CC1S_TI1 | TIM_CCMR_CC2S_TI1); + + /* Capture period on IC1/3 rising edge, duty cycle on IC2/4 falling. */ + regmap_update_bits(priv->regmap, TIM_CCER, pwm->hwpwm < 2 ? + TIM_CCER_CC12P : TIM_CCER_CC34P, pwm->hwpwm < 2 ? + TIM_CCER_CC2P : TIM_CCER_CC4P); + + ret = stm32_pwm_raw_capture(priv, pwm, tmo_ms, &raw_prd, &raw_dty); + if (ret) + goto stop; + + /* + * Got a capture. Try to improve accuracy at high rates: + * - decrease counter clock prescaler, scale up to max rate. + * - use input prescaler, capture once every /2 /4 or /8 edges. + */ + if (raw_prd) { + u32 max_arr = priv->max_arr - 0x1000; /* arbitrary margin */ + + scale = max_arr / min(max_arr, raw_prd); + } else { + scale = priv->max_arr; /* bellow resolution, use max scale */ + } + + if (psc && scale > 1) { + /* 2nd measure with new scale */ + psc /= scale; + regmap_write(priv->regmap, TIM_PSC, psc); + ret = stm32_pwm_raw_capture(priv, pwm, tmo_ms, &raw_prd, + &raw_dty); + if (ret) + goto stop; + } + + /* Compute intermediate period not to exceed timeout at low rates */ + prd = (unsigned long long)raw_prd * (psc + 1) * NSEC_PER_SEC; + do_div(prd, rate); + + for (icpsc = 0; icpsc < MAX_TIM_ICPSC ; icpsc++) { + /* input prescaler: also keep arbitrary margin */ + if (raw_prd >= (priv->max_arr - 0x1000) >> (icpsc + 1)) + break; + if (prd >= (tmo_ms * NSEC_PER_MSEC) >> (icpsc + 2)) + break; + } + + if (!icpsc) + goto done; + + /* Last chance to improve period accuracy, using input prescaler */ + regmap_update_bits(priv->regmap, + pwm->hwpwm < 2 ? TIM_CCMR1 : TIM_CCMR2, + TIM_CCMR_IC1PSC | TIM_CCMR_IC2PSC, + FIELD_PREP(TIM_CCMR_IC1PSC, icpsc) | + FIELD_PREP(TIM_CCMR_IC2PSC, icpsc)); + + ret = stm32_pwm_raw_capture(priv, pwm, tmo_ms, &raw_prd, &raw_dty); + if (ret) + goto stop; + + if (raw_dty >= (raw_prd >> icpsc)) { + /* + * We may fall here using input prescaler, when input + * capture starts on high side (before falling edge). + * Example with icpsc to capture on each 4 events: + * + * start 1st capture 2nd capture + * v v v + * ___ _____ _____ _____ _____ ____ + * TI1..4 |__| |__| |__| |__| |__| + * v v . . . . . v v + * icpsc1/3: . 0 . 1 . 2 . 3 . 0 + * icpsc2/4: 0 1 2 3 0 + * v v v v + * CCR1/3 ......t0..............................t2 + * CCR2/4 ..t1..............................t1'... + * . . . + * Capture0: .<----------------------------->. + * Capture1: .<-------------------------->. . + * . . . + * Period: .<------> . . + * Low side: .<>. + * + * Result: + * - Period = Capture0 / icpsc + * - Duty = Period - Low side = Period - (Capture0 - Capture1) + */ + raw_dty = (raw_prd >> icpsc) - (raw_prd - raw_dty); + } + +done: + prd = (unsigned long long)raw_prd * (psc + 1) * NSEC_PER_SEC; + result->period = DIV_ROUND_UP_ULL(prd, rate << icpsc); + dty = (unsigned long long)raw_dty * (psc + 1) * NSEC_PER_SEC; + result->duty_cycle = DIV_ROUND_UP_ULL(dty, rate); +stop: + regmap_write(priv->regmap, TIM_CCER, 0); + regmap_write(priv->regmap, pwm->hwpwm < 2 ? TIM_CCMR1 : TIM_CCMR2, 0); + regmap_write(priv->regmap, TIM_PSC, 0); +clk_dis: + clk_disable(priv->clk); +unlock: + mutex_unlock(&priv->lock); + + return ret; +} + static int stm32_pwm_config(struct stm32_pwm *priv, int ch, int duty_ns, int period_ns) { @@ -230,6 +484,7 @@ static int stm32_pwm_apply_locked(struct pwm_chip *chip, struct pwm_device *pwm, static const struct pwm_ops stm32pwm_ops = { .owner = THIS_MODULE, .apply = stm32_pwm_apply_locked, + .capture = IS_ENABLED(CONFIG_DMA_ENGINE) ? stm32_pwm_capture : NULL, }; static int stm32_pwm_set_breakinput(struct stm32_pwm *priv, diff --git a/drivers/rapidio/devices/rio_mport_cdev.c b/drivers/rapidio/devices/rio_mport_cdev.c index 0434ab7b6497..a8cb8d2f2abb 100644 --- a/drivers/rapidio/devices/rio_mport_cdev.c +++ b/drivers/rapidio/devices/rio_mport_cdev.c @@ -975,7 +975,7 @@ static int rio_mport_transfer_ioctl(struct file *filp, void __user *arg) priv->md->properties.transfer_mode) == 0) return -ENODEV; - transfer = vmalloc(transaction.count * sizeof(*transfer)); + transfer = vmalloc(array_size(sizeof(*transfer), transaction.count)); if (!transfer) return -ENOMEM; diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c index 161b927d9de1..fd7b517132ac 100644 --- a/drivers/rapidio/rio-scan.c +++ b/drivers/rapidio/rio-scan.c @@ -425,9 +425,9 @@ static struct rio_dev *rio_setup_device(struct rio_net *net, rswitch = rdev->rswitch; rswitch->port_ok = 0; spin_lock_init(&rswitch->lock); - rswitch->route_table = kzalloc(sizeof(u8)* - RIO_MAX_ROUTE_ENTRIES(port->sys_size), - GFP_KERNEL); + rswitch->route_table = + kzalloc(RIO_MAX_ROUTE_ENTRIES(port->sys_size), + GFP_KERNEL); if (!rswitch->route_table) goto cleanup; /* Initialize switch route table */ diff --git a/drivers/regulator/act8865-regulator.c b/drivers/regulator/act8865-regulator.c index 7652477e6a9d..21e20483bd91 100644 --- a/drivers/regulator/act8865-regulator.c +++ b/drivers/regulator/act8865-regulator.c @@ -424,9 +424,10 @@ static int act8865_pdata_from_dt(struct device *dev, if (matched <= 0) return matched; - pdata->regulators = devm_kzalloc(dev, - sizeof(struct act8865_regulator_data) * - num_matches, GFP_KERNEL); + pdata->regulators = devm_kcalloc(dev, + num_matches, + sizeof(struct act8865_regulator_data), + GFP_KERNEL); if (!pdata->regulators) return -ENOMEM; diff --git a/drivers/regulator/as3711-regulator.c b/drivers/regulator/as3711-regulator.c index 874d415d6b4f..565a71343a8e 100644 --- a/drivers/regulator/as3711-regulator.c +++ b/drivers/regulator/as3711-regulator.c @@ -239,8 +239,10 @@ static int as3711_regulator_probe(struct platform_device *pdev) } } - regs = devm_kzalloc(&pdev->dev, AS3711_REGULATOR_NUM * - sizeof(struct as3711_regulator), GFP_KERNEL); + regs = devm_kcalloc(&pdev->dev, + AS3711_REGULATOR_NUM, + sizeof(struct as3711_regulator), + GFP_KERNEL); if (!regs) return -ENOMEM; diff --git a/drivers/regulator/bcm590xx-regulator.c b/drivers/regulator/bcm590xx-regulator.c index 9dd715407b39..92d6d7b10cf7 100644 --- a/drivers/regulator/bcm590xx-regulator.c +++ b/drivers/regulator/bcm590xx-regulator.c @@ -383,8 +383,10 @@ static int bcm590xx_probe(struct platform_device *pdev) platform_set_drvdata(pdev, pmu); - pmu->desc = devm_kzalloc(&pdev->dev, BCM590XX_NUM_REGS * - sizeof(struct regulator_desc), GFP_KERNEL); + pmu->desc = devm_kcalloc(&pdev->dev, + BCM590XX_NUM_REGS, + sizeof(struct regulator_desc), + GFP_KERNEL); if (!pmu->desc) return -ENOMEM; diff --git a/drivers/regulator/da9063-regulator.c b/drivers/regulator/da9063-regulator.c index 6a8f9cd69f52..2df26f36c687 100644 --- a/drivers/regulator/da9063-regulator.c +++ b/drivers/regulator/da9063-regulator.c @@ -681,8 +681,8 @@ static struct da9063_regulators_pdata *da9063_parse_regulators_dt( if (!pdata) return ERR_PTR(-ENOMEM); - pdata->regulator_data = devm_kzalloc(&pdev->dev, - num * sizeof(*pdata->regulator_data), + pdata->regulator_data = devm_kcalloc(&pdev->dev, + num, sizeof(*pdata->regulator_data), GFP_KERNEL); if (!pdata->regulator_data) return ERR_PTR(-ENOMEM); diff --git a/drivers/regulator/gpio-regulator.c b/drivers/regulator/gpio-regulator.c index a86b8997bb54..b2f5ec4f658a 100644 --- a/drivers/regulator/gpio-regulator.c +++ b/drivers/regulator/gpio-regulator.c @@ -172,8 +172,8 @@ of_get_gpio_regulator_config(struct device *dev, struct device_node *np, if (ret > 0) { config->nr_gpios = ret; - config->gpios = devm_kzalloc(dev, - sizeof(struct gpio) * config->nr_gpios, + config->gpios = devm_kcalloc(dev, + config->nr_gpios, sizeof(struct gpio), GFP_KERNEL); if (!config->gpios) return ERR_PTR(-ENOMEM); @@ -214,9 +214,9 @@ of_get_gpio_regulator_config(struct device *dev, struct device_node *np, return ERR_PTR(-EINVAL); } - config->states = devm_kzalloc(dev, - sizeof(struct gpio_regulator_state) - * (proplen / 2), + config->states = devm_kcalloc(dev, + proplen / 2, + sizeof(struct gpio_regulator_state), GFP_KERNEL); if (!config->states) return ERR_PTR(-ENOMEM); diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c index 66bbaa999433..cc52779b53f7 100644 --- a/drivers/regulator/max1586.c +++ b/drivers/regulator/max1586.c @@ -194,8 +194,10 @@ static int of_get_max1586_platform_data(struct device *dev, if (matched <= 0) return matched; - pdata->subdevs = devm_kzalloc(dev, sizeof(struct max1586_subdev_data) * - matched, GFP_KERNEL); + pdata->subdevs = devm_kcalloc(dev, + matched, + sizeof(struct max1586_subdev_data), + GFP_KERNEL); if (!pdata->subdevs) return -ENOMEM; diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c index a6183425f27d..4cf6897a401f 100644 --- a/drivers/regulator/max8660.c +++ b/drivers/regulator/max8660.c @@ -351,8 +351,10 @@ static int max8660_pdata_from_dt(struct device *dev, if (matched <= 0) return matched; - pdata->subdevs = devm_kzalloc(dev, sizeof(struct max8660_subdev_data) * - matched, GFP_KERNEL); + pdata->subdevs = devm_kcalloc(dev, + matched, + sizeof(struct max8660_subdev_data), + GFP_KERNEL); if (!pdata->subdevs) return -ENOMEM; diff --git a/drivers/regulator/max8997-regulator.c b/drivers/regulator/max8997-regulator.c index 559b9ac45404..a8ea30ee18a6 100644 --- a/drivers/regulator/max8997-regulator.c +++ b/drivers/regulator/max8997-regulator.c @@ -929,8 +929,9 @@ static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev, /* count the number of regulators to be supported in pmic */ pdata->num_regulators = of_get_child_count(regulators_np); - rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) * - pdata->num_regulators, GFP_KERNEL); + rdata = devm_kcalloc(&pdev->dev, + pdata->num_regulators, sizeof(*rdata), + GFP_KERNEL); if (!rdata) { of_node_put(regulators_np); return -ENOMEM; diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c index 6a2b61c012b5..6b9f262ebbb0 100644 --- a/drivers/regulator/max8998.c +++ b/drivers/regulator/max8998.c @@ -670,8 +670,9 @@ static int max8998_pmic_dt_parse_pdata(struct max8998_dev *iodev, /* count the number of regulators to be supported in pmic */ pdata->num_regulators = of_get_child_count(regulators_np); - rdata = devm_kzalloc(iodev->dev, sizeof(*rdata) * - pdata->num_regulators, GFP_KERNEL); + rdata = devm_kcalloc(iodev->dev, + pdata->num_regulators, sizeof(*rdata), + GFP_KERNEL); if (!rdata) { of_node_put(regulators_np); return -ENOMEM; diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c index 41271aeea63e..da4fb9824757 100644 --- a/drivers/regulator/mc13xxx-regulator-core.c +++ b/drivers/regulator/mc13xxx-regulator-core.c @@ -171,7 +171,7 @@ struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt( if (!parent) return NULL; - data = devm_kzalloc(&pdev->dev, sizeof(*data) * priv->num_regulators, + data = devm_kcalloc(&pdev->dev, priv->num_regulators, sizeof(*data), GFP_KERNEL); if (!data) { of_node_put(parent); diff --git a/drivers/regulator/pbias-regulator.c b/drivers/regulator/pbias-regulator.c index 8f782d22fdbe..92b41a6a4dc2 100644 --- a/drivers/regulator/pbias-regulator.c +++ b/drivers/regulator/pbias-regulator.c @@ -173,8 +173,9 @@ static int pbias_regulator_probe(struct platform_device *pdev) if (count < 0) return count; - drvdata = devm_kzalloc(&pdev->dev, sizeof(struct pbias_regulator_data) - * count, GFP_KERNEL); + drvdata = devm_kcalloc(&pdev->dev, + count, sizeof(struct pbias_regulator_data), + GFP_KERNEL); if (!drvdata) return -ENOMEM; diff --git a/drivers/regulator/rc5t583-regulator.c b/drivers/regulator/rc5t583-regulator.c index d0f1340168b1..2ec51af43673 100644 --- a/drivers/regulator/rc5t583-regulator.c +++ b/drivers/regulator/rc5t583-regulator.c @@ -132,8 +132,10 @@ static int rc5t583_regulator_probe(struct platform_device *pdev) return -ENODEV; } - regs = devm_kzalloc(&pdev->dev, RC5T583_REGULATOR_MAX * - sizeof(struct rc5t583_regulator), GFP_KERNEL); + regs = devm_kcalloc(&pdev->dev, + RC5T583_REGULATOR_MAX, + sizeof(struct rc5t583_regulator), + GFP_KERNEL); if (!regs) return -ENOMEM; diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index 7726b874e539..d1207ec683db 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -1139,8 +1139,8 @@ static int s2mps11_pmic_probe(struct platform_device *pdev) return -EINVAL; } - s2mps11->ext_control_gpio = devm_kmalloc(&pdev->dev, - sizeof(*s2mps11->ext_control_gpio) * rdev_num, + s2mps11->ext_control_gpio = devm_kmalloc_array(&pdev->dev, + rdev_num, sizeof(*s2mps11->ext_control_gpio), GFP_KERNEL); if (!s2mps11->ext_control_gpio) return -ENOMEM; @@ -1162,7 +1162,7 @@ static int s2mps11_pmic_probe(struct platform_device *pdev) } } - rdata = kzalloc(sizeof(*rdata) * rdev_num, GFP_KERNEL); + rdata = kcalloc(rdev_num, sizeof(*rdata), GFP_KERNEL); if (!rdata) return -ENOMEM; diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c index b8443a360646..0cbc980753c2 100644 --- a/drivers/regulator/s5m8767.c +++ b/drivers/regulator/s5m8767.c @@ -553,13 +553,15 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, /* count the number of regulators to be supported in pmic */ pdata->num_regulators = of_get_child_count(regulators_np); - rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) * - pdata->num_regulators, GFP_KERNEL); + rdata = devm_kcalloc(&pdev->dev, + pdata->num_regulators, sizeof(*rdata), + GFP_KERNEL); if (!rdata) return -ENOMEM; - rmode = devm_kzalloc(&pdev->dev, sizeof(*rmode) * - pdata->num_regulators, GFP_KERNEL); + rmode = devm_kcalloc(&pdev->dev, + pdata->num_regulators, sizeof(*rmode), + GFP_KERNEL); if (!rmode) return -ENOMEM; diff --git a/drivers/regulator/ti-abb-regulator.c b/drivers/regulator/ti-abb-regulator.c index d2f994298753..cced1ffb896c 100644 --- a/drivers/regulator/ti-abb-regulator.c +++ b/drivers/regulator/ti-abb-regulator.c @@ -532,13 +532,13 @@ static int ti_abb_init_table(struct device *dev, struct ti_abb *abb, } num_entries /= num_values; - info = devm_kzalloc(dev, sizeof(*info) * num_entries, GFP_KERNEL); + info = devm_kcalloc(dev, num_entries, sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; abb->info = info; - volt_table = devm_kzalloc(dev, sizeof(unsigned int) * num_entries, + volt_table = devm_kcalloc(dev, num_entries, sizeof(unsigned int), GFP_KERNEL); if (!volt_table) return -ENOMEM; diff --git a/drivers/regulator/tps65090-regulator.c b/drivers/regulator/tps65090-regulator.c index 2d398fa3b720..edaef9e4dc74 100644 --- a/drivers/regulator/tps65090-regulator.c +++ b/drivers/regulator/tps65090-regulator.c @@ -331,8 +331,9 @@ static struct tps65090_platform_data *tps65090_parse_dt_reg_data( if (!tps65090_pdata) return ERR_PTR(-ENOMEM); - reg_pdata = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX * - sizeof(*reg_pdata), GFP_KERNEL); + reg_pdata = devm_kcalloc(&pdev->dev, + TPS65090_REGULATOR_MAX, sizeof(*reg_pdata), + GFP_KERNEL); if (!reg_pdata) return ERR_PTR(-ENOMEM); @@ -429,8 +430,9 @@ static int tps65090_regulator_probe(struct platform_device *pdev) return tps65090_pdata ? PTR_ERR(tps65090_pdata) : -EINVAL; } - pmic = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX * sizeof(*pmic), - GFP_KERNEL); + pmic = devm_kcalloc(&pdev->dev, + TPS65090_REGULATOR_MAX, sizeof(*pmic), + GFP_KERNEL); if (!pmic) return -ENOMEM; diff --git a/drivers/regulator/tps65217-regulator.c b/drivers/regulator/tps65217-regulator.c index 7b12e880d1ea..fc12badf3805 100644 --- a/drivers/regulator/tps65217-regulator.c +++ b/drivers/regulator/tps65217-regulator.c @@ -229,8 +229,9 @@ static int tps65217_regulator_probe(struct platform_device *pdev) unsigned int val; /* Allocate memory for strobes */ - tps->strobes = devm_kzalloc(&pdev->dev, sizeof(u8) * - TPS65217_NUM_REGULATOR, GFP_KERNEL); + tps->strobes = devm_kcalloc(&pdev->dev, + TPS65217_NUM_REGULATOR, sizeof(u8), + GFP_KERNEL); platform_set_drvdata(pdev, tps); diff --git a/drivers/regulator/tps65218-regulator.c b/drivers/regulator/tps65218-regulator.c index 1827185beacc..6209beee1018 100644 --- a/drivers/regulator/tps65218-regulator.c +++ b/drivers/regulator/tps65218-regulator.c @@ -324,8 +324,9 @@ static int tps65218_regulator_probe(struct platform_device *pdev) config.regmap = tps->regmap; /* Allocate memory for strobes */ - tps->strobes = devm_kzalloc(&pdev->dev, sizeof(u8) * - TPS65218_NUM_REGULATOR, GFP_KERNEL); + tps->strobes = devm_kcalloc(&pdev->dev, + TPS65218_NUM_REGULATOR, sizeof(u8), + GFP_KERNEL); if (!tps->strobes) return -ENOMEM; diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c index 81672a58fcc2..02ccdaa226a7 100644 --- a/drivers/regulator/tps65910-regulator.c +++ b/drivers/regulator/tps65910-regulator.c @@ -1131,18 +1131,24 @@ static int tps65910_probe(struct platform_device *pdev) return -ENODEV; } - pmic->desc = devm_kzalloc(&pdev->dev, pmic->num_regulators * - sizeof(struct regulator_desc), GFP_KERNEL); + pmic->desc = devm_kcalloc(&pdev->dev, + pmic->num_regulators, + sizeof(struct regulator_desc), + GFP_KERNEL); if (!pmic->desc) return -ENOMEM; - pmic->info = devm_kzalloc(&pdev->dev, pmic->num_regulators * - sizeof(struct tps_info *), GFP_KERNEL); + pmic->info = devm_kcalloc(&pdev->dev, + pmic->num_regulators, + sizeof(struct tps_info *), + GFP_KERNEL); if (!pmic->info) return -ENOMEM; - pmic->rdev = devm_kzalloc(&pdev->dev, pmic->num_regulators * - sizeof(struct regulator_dev *), GFP_KERNEL); + pmic->rdev = devm_kcalloc(&pdev->dev, + pmic->num_regulators, + sizeof(struct regulator_dev *), + GFP_KERNEL); if (!pmic->rdev) return -ENOMEM; diff --git a/drivers/regulator/tps80031-regulator.c b/drivers/regulator/tps80031-regulator.c index d4cc60ad18ae..1001147404c3 100644 --- a/drivers/regulator/tps80031-regulator.c +++ b/drivers/regulator/tps80031-regulator.c @@ -691,8 +691,8 @@ static int tps80031_regulator_probe(struct platform_device *pdev) return -EINVAL; } - pmic = devm_kzalloc(&pdev->dev, - TPS80031_REGULATOR_MAX * sizeof(*pmic), GFP_KERNEL); + pmic = devm_kcalloc(&pdev->dev, + TPS80031_REGULATOR_MAX, sizeof(*pmic), GFP_KERNEL); if (!pmic) return -ENOMEM; diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index 027274008b08..cd1c168fd188 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -24,7 +24,6 @@ config IMX_REMOTEPROC config OMAP_REMOTEPROC tristate "OMAP remoteproc support" - depends on HAS_DMA depends on ARCH_OMAP4 || SOC_OMAP5 depends on OMAP_IOMMU select MAILBOX diff --git a/drivers/remoteproc/da8xx_remoteproc.c b/drivers/remoteproc/da8xx_remoteproc.c index bf3b9034c319..b668e32996e2 100644 --- a/drivers/remoteproc/da8xx_remoteproc.c +++ b/drivers/remoteproc/da8xx_remoteproc.c @@ -25,7 +25,7 @@ #include "remoteproc_internal.h" static char *da8xx_fw_name; -module_param(da8xx_fw_name, charp, S_IRUGO); +module_param(da8xx_fw_name, charp, 0444); MODULE_PARM_DESC(da8xx_fw_name, "Name of DSP firmware file in /lib/firmware (if not specified defaults to 'rproc-dsp-fw')"); @@ -138,6 +138,7 @@ static int da8xx_rproc_start(struct rproc *rproc) struct device *dev = rproc->dev.parent; struct da8xx_rproc *drproc = (struct da8xx_rproc *)rproc->priv; struct clk *dsp_clk = drproc->dsp_clk; + int ret; /* hw requires the start (boot) address be on 1KB boundary */ if (rproc->bootaddr & 0x3ff) { @@ -148,7 +149,12 @@ static int da8xx_rproc_start(struct rproc *rproc) writel(rproc->bootaddr, drproc->bootreg); - clk_enable(dsp_clk); + ret = clk_prepare_enable(dsp_clk); + if (ret) { + dev_err(dev, "clk_prepare_enable() failed: %d\n", ret); + return ret; + } + davinci_clk_reset_deassert(dsp_clk); return 0; @@ -159,7 +165,7 @@ static int da8xx_rproc_stop(struct rproc *rproc) struct da8xx_rproc *drproc = rproc->priv; davinci_clk_reset_assert(drproc->dsp_clk); - clk_disable(drproc->dsp_clk); + clk_disable_unprepare(drproc->dsp_clk); return 0; } diff --git a/drivers/remoteproc/qcom_q6v5_pil.c b/drivers/remoteproc/qcom_q6v5_pil.c index cbbafdcaaecb..2bf8e7c49f2a 100644 --- a/drivers/remoteproc/qcom_q6v5_pil.c +++ b/drivers/remoteproc/qcom_q6v5_pil.c @@ -57,6 +57,8 @@ #define RMB_PMI_META_DATA_REG 0x10 #define RMB_PMI_CODE_START_REG 0x14 #define RMB_PMI_CODE_LENGTH_REG 0x18 +#define RMB_MBA_MSS_STATUS 0x40 +#define RMB_MBA_ALT_RESET 0x44 #define RMB_CMD_META_DATA_READY 0x1 #define RMB_CMD_LOAD_READY 0x2 @@ -104,6 +106,13 @@ #define QDSP6SS_XO_CBCR 0x0038 #define QDSP6SS_ACC_OVERRIDE_VAL 0x20 +/* QDSP6v65 parameters */ +#define QDSP6SS_SLEEP 0x3C +#define QDSP6SS_BOOT_CORE_START 0x400 +#define QDSP6SS_BOOT_CMD 0x404 +#define SLEEP_CHECK_MAX_LOOPS 200 +#define BOOT_FSM_TIMEOUT 10000 + struct reg_info { struct regulator *reg; int uV; @@ -121,9 +130,11 @@ struct rproc_hexagon_res { struct qcom_mss_reg_res *proxy_supply; struct qcom_mss_reg_res *active_supply; char **proxy_clk_names; + char **reset_clk_names; char **active_clk_names; int version; bool need_mem_protection; + bool has_alt_reset; }; struct q6v5 { @@ -143,9 +154,15 @@ struct q6v5 { struct qcom_smem_state *state; unsigned stop_bit; + int handover_irq; + + bool proxy_unvoted; + struct clk *active_clks[8]; + struct clk *reset_clks[4]; struct clk *proxy_clks[4]; int active_clk_count; + int reset_clk_count; int proxy_clk_count; struct reg_info active_regs[1]; @@ -166,10 +183,12 @@ struct q6v5 { void *mpss_region; size_t mpss_size; + struct qcom_rproc_glink glink_subdev; struct qcom_rproc_subdev smd_subdev; struct qcom_rproc_ssr ssr_subdev; struct qcom_sysmon *sysmon; bool need_mem_protection; + bool has_alt_reset; int mpss_perm; int mba_perm; int version; @@ -179,6 +198,7 @@ enum { MSS_MSM8916, MSS_MSM8974, MSS_MSM8996, + MSS_SDM845, }; static int q6v5_regulator_init(struct device *dev, struct reg_info *regs, @@ -333,6 +353,29 @@ static int q6v5_load(struct rproc *rproc, const struct firmware *fw) return 0; } +static int q6v5_reset_assert(struct q6v5 *qproc) +{ + if (qproc->has_alt_reset) + return reset_control_reset(qproc->mss_restart); + else + return reset_control_assert(qproc->mss_restart); +} + +static int q6v5_reset_deassert(struct q6v5 *qproc) +{ + int ret; + + if (qproc->has_alt_reset) { + writel(1, qproc->rmb_base + RMB_MBA_ALT_RESET); + ret = reset_control_reset(qproc->mss_restart); + writel(0, qproc->rmb_base + RMB_MBA_ALT_RESET); + } else { + ret = reset_control_deassert(qproc->mss_restart); + } + + return ret; +} + static int q6v5_rmb_pbl_wait(struct q6v5 *qproc, int ms) { unsigned long timeout; @@ -385,8 +428,35 @@ static int q6v5proc_reset(struct q6v5 *qproc) int ret; int i; + if (qproc->version == MSS_SDM845) { + val = readl(qproc->reg_base + QDSP6SS_SLEEP); + val |= 0x1; + writel(val, qproc->reg_base + QDSP6SS_SLEEP); - if (qproc->version == MSS_MSM8996) { + ret = readl_poll_timeout(qproc->reg_base + QDSP6SS_SLEEP, + val, !(val & BIT(31)), 1, + SLEEP_CHECK_MAX_LOOPS); + if (ret) { + dev_err(qproc->dev, "QDSP6SS Sleep clock timed out\n"); + return -ETIMEDOUT; + } + + /* De-assert QDSP6 stop core */ + writel(1, qproc->reg_base + QDSP6SS_BOOT_CORE_START); + /* Trigger boot FSM */ + writel(1, qproc->reg_base + QDSP6SS_BOOT_CMD); + + ret = readl_poll_timeout(qproc->rmb_base + RMB_MBA_MSS_STATUS, + val, (val & BIT(0)) != 0, 10, BOOT_FSM_TIMEOUT); + if (ret) { + dev_err(qproc->dev, "Boot FSM failed to complete.\n"); + /* Reset the modem so that boot FSM is in reset state */ + q6v5_reset_deassert(qproc); + return ret; + } + + goto pbl_wait; + } else if (qproc->version == MSS_MSM8996) { /* Override the ACC value if required */ writel(QDSP6SS_ACC_OVERRIDE_VAL, qproc->reg_base + QDSP6SS_STRAP_ACC); @@ -494,6 +564,7 @@ static int q6v5proc_reset(struct q6v5 *qproc) val &= ~Q6SS_STOP_CORE; writel(val, qproc->reg_base + QDSP6SS_RESET_REG); +pbl_wait: /* Wait for PBL status */ ret = q6v5_rmb_pbl_wait(qproc, 1000); if (ret == -ETIMEDOUT) { @@ -615,7 +686,7 @@ static int q6v5_mpss_load(struct q6v5 *qproc) struct elf32_hdr *ehdr; phys_addr_t mpss_reloc; phys_addr_t boot_addr; - phys_addr_t min_addr = (phys_addr_t)ULLONG_MAX; + phys_addr_t min_addr = PHYS_ADDR_MAX; phys_addr_t max_addr = 0; bool relocate = false; char seg_name[10]; @@ -727,11 +798,15 @@ static int q6v5_start(struct rproc *rproc) int xfermemop_ret; int ret; + qproc->proxy_unvoted = false; + + enable_irq(qproc->handover_irq); + ret = q6v5_regulator_enable(qproc, qproc->proxy_regs, qproc->proxy_reg_count); if (ret) { dev_err(qproc->dev, "failed to enable proxy supplies\n"); - return ret; + goto disable_irqs; } ret = q6v5_clk_enable(qproc->dev, qproc->proxy_clks, @@ -747,12 +822,20 @@ static int q6v5_start(struct rproc *rproc) dev_err(qproc->dev, "failed to enable supplies\n"); goto disable_proxy_clk; } - ret = reset_control_deassert(qproc->mss_restart); + + ret = q6v5_clk_enable(qproc->dev, qproc->reset_clks, + qproc->reset_clk_count); if (ret) { - dev_err(qproc->dev, "failed to deassert mss restart\n"); + dev_err(qproc->dev, "failed to enable reset clocks\n"); goto disable_vdd; } + ret = q6v5_reset_deassert(qproc); + if (ret) { + dev_err(qproc->dev, "failed to deassert mss restart\n"); + goto disable_reset_clks; + } + ret = q6v5_clk_enable(qproc->dev, qproc->active_clks, qproc->active_clk_count); if (ret) { @@ -761,13 +844,11 @@ static int q6v5_start(struct rproc *rproc) } /* Assign MBA image access in DDR to q6 */ - xfermemop_ret = q6v5_xfer_mem_ownership(qproc, &qproc->mba_perm, true, - qproc->mba_phys, - qproc->mba_size); - if (xfermemop_ret) { + ret = q6v5_xfer_mem_ownership(qproc, &qproc->mba_perm, true, + qproc->mba_phys, qproc->mba_size); + if (ret) { dev_err(qproc->dev, - "assigning Q6 access to mba memory failed: %d\n", - xfermemop_ret); + "assigning Q6 access to mba memory failed: %d\n", ret); goto disable_active_clks; } @@ -810,11 +891,6 @@ static int q6v5_start(struct rproc *rproc) "Failed to reclaim mba buffer system may become unstable\n"); qproc->running = true; - q6v5_clk_disable(qproc->dev, qproc->proxy_clks, - qproc->proxy_clk_count); - q6v5_regulator_disable(qproc, qproc->proxy_regs, - qproc->proxy_reg_count); - return 0; reclaim_mpss: @@ -842,7 +918,10 @@ disable_active_clks: qproc->active_clk_count); assert_reset: - reset_control_assert(qproc->mss_restart); + q6v5_reset_assert(qproc); +disable_reset_clks: + q6v5_clk_disable(qproc->dev, qproc->reset_clks, + qproc->reset_clk_count); disable_vdd: q6v5_regulator_disable(qproc, qproc->active_regs, qproc->active_reg_count); @@ -853,6 +932,9 @@ disable_proxy_reg: q6v5_regulator_disable(qproc, qproc->proxy_regs, qproc->proxy_reg_count); +disable_irqs: + disable_irq(qproc->handover_irq); + return ret; } @@ -892,7 +974,19 @@ static int q6v5_stop(struct rproc *rproc) qproc->mpss_phys, qproc->mpss_size); WARN_ON(ret); - reset_control_assert(qproc->mss_restart); + q6v5_reset_assert(qproc); + + disable_irq(qproc->handover_irq); + + if (!qproc->proxy_unvoted) { + q6v5_clk_disable(qproc->dev, qproc->proxy_clks, + qproc->proxy_clk_count); + q6v5_regulator_disable(qproc, qproc->proxy_regs, + qproc->proxy_reg_count); + } + + q6v5_clk_disable(qproc->dev, qproc->reset_clks, + qproc->reset_clk_count); q6v5_clk_disable(qproc->dev, qproc->active_clks, qproc->active_clk_count); q6v5_regulator_disable(qproc, qproc->active_regs, @@ -960,7 +1054,7 @@ static irqreturn_t q6v5_fatal_interrupt(int irq, void *dev) return IRQ_HANDLED; } -static irqreturn_t q6v5_handover_interrupt(int irq, void *dev) +static irqreturn_t q6v5_ready_interrupt(int irq, void *dev) { struct q6v5 *qproc = dev; @@ -968,6 +1062,20 @@ static irqreturn_t q6v5_handover_interrupt(int irq, void *dev) return IRQ_HANDLED; } +static irqreturn_t q6v5_handover_interrupt(int irq, void *dev) +{ + struct q6v5 *qproc = dev; + + q6v5_clk_disable(qproc->dev, qproc->proxy_clks, + qproc->proxy_clk_count); + q6v5_regulator_disable(qproc, qproc->proxy_regs, + qproc->proxy_reg_count); + + qproc->proxy_unvoted = true; + + return IRQ_HANDLED; +} + static irqreturn_t q6v5_stop_ack_interrupt(int irq, void *dev) { struct q6v5 *qproc = dev; @@ -1051,22 +1159,23 @@ static int q6v5_request_irq(struct q6v5 *qproc, const char *name, irq_handler_t thread_fn) { + int irq; int ret; - ret = platform_get_irq_byname(pdev, name); - if (ret < 0) { + irq = platform_get_irq_byname(pdev, name); + if (irq < 0) { dev_err(&pdev->dev, "no %s IRQ defined\n", name); - return ret; + return irq; } - ret = devm_request_threaded_irq(&pdev->dev, ret, + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, thread_fn, IRQF_TRIGGER_RISING | IRQF_ONESHOT, "q6v5", qproc); if (ret) dev_err(&pdev->dev, "request %s IRQ failed\n", name); - return ret; + return ret ? : irq; } static int q6v5_alloc_memory_region(struct q6v5 *qproc) @@ -1157,6 +1266,14 @@ static int q6v5_probe(struct platform_device *pdev) } qproc->proxy_clk_count = ret; + ret = q6v5_init_clocks(&pdev->dev, qproc->reset_clks, + desc->reset_clk_names); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to get reset clocks.\n"); + goto free_rproc; + } + qproc->reset_clk_count = ret; + ret = q6v5_init_clocks(&pdev->dev, qproc->active_clks, desc->active_clk_names); if (ret < 0) { @@ -1186,6 +1303,7 @@ static int q6v5_probe(struct platform_device *pdev) goto free_rproc; qproc->version = desc->version; + qproc->has_alt_reset = desc->has_alt_reset; qproc->need_mem_protection = desc->need_mem_protection; ret = q6v5_request_irq(qproc, pdev, "wdog", q6v5_wdog_interrupt); if (ret < 0) @@ -1195,9 +1313,15 @@ static int q6v5_probe(struct platform_device *pdev) if (ret < 0) goto free_rproc; + ret = q6v5_request_irq(qproc, pdev, "ready", q6v5_ready_interrupt); + if (ret < 0) + goto free_rproc; + ret = q6v5_request_irq(qproc, pdev, "handover", q6v5_handover_interrupt); if (ret < 0) goto free_rproc; + qproc->handover_irq = ret; + disable_irq(qproc->handover_irq); ret = q6v5_request_irq(qproc, pdev, "stop-ack", q6v5_stop_ack_interrupt); if (ret < 0) @@ -1210,6 +1334,7 @@ static int q6v5_probe(struct platform_device *pdev) } qproc->mpss_perm = BIT(QCOM_SCM_VMID_HLOS); qproc->mba_perm = BIT(QCOM_SCM_VMID_HLOS); + qcom_add_glink_subdev(rproc, &qproc->glink_subdev); qcom_add_smd_subdev(rproc, &qproc->smd_subdev); qcom_add_ssr_subdev(rproc, &qproc->ssr_subdev, "mpss"); qproc->sysmon = qcom_add_sysmon_subdev(rproc, "modem", 0x12); @@ -1233,6 +1358,7 @@ static int q6v5_remove(struct platform_device *pdev) rproc_del(qproc->rproc); qcom_remove_sysmon_subdev(qproc->sysmon); + qcom_remove_glink_subdev(qproc->rproc, &qproc->glink_subdev); qcom_remove_smd_subdev(qproc->rproc, &qproc->smd_subdev); qcom_remove_ssr_subdev(qproc->rproc, &qproc->ssr_subdev); rproc_free(qproc->rproc); @@ -1240,6 +1366,31 @@ static int q6v5_remove(struct platform_device *pdev) return 0; } +static const struct rproc_hexagon_res sdm845_mss = { + .hexagon_mba_image = "mba.mbn", + .proxy_clk_names = (char*[]){ + "xo", + "axis2", + "prng", + NULL + }, + .reset_clk_names = (char*[]){ + "iface", + "snoc_axi", + NULL + }, + .active_clk_names = (char*[]){ + "bus", + "mem", + "gpll0_mss", + "mnoc_axi", + NULL + }, + .need_mem_protection = true, + .has_alt_reset = true, + .version = MSS_SDM845, +}; + static const struct rproc_hexagon_res msm8996_mss = { .hexagon_mba_image = "mba.mbn", .proxy_clk_names = (char*[]){ @@ -1255,6 +1406,7 @@ static const struct rproc_hexagon_res msm8996_mss = { NULL }, .need_mem_protection = true, + .has_alt_reset = false, .version = MSS_MSM8996, }; @@ -1286,6 +1438,7 @@ static const struct rproc_hexagon_res msm8916_mss = { NULL }, .need_mem_protection = false, + .has_alt_reset = false, .version = MSS_MSM8916, }; @@ -1325,6 +1478,7 @@ static const struct rproc_hexagon_res msm8974_mss = { NULL }, .need_mem_protection = false, + .has_alt_reset = false, .version = MSS_MSM8974, }; @@ -1333,6 +1487,7 @@ static const struct of_device_id q6v5_of_match[] = { { .compatible = "qcom,msm8916-mss-pil", .data = &msm8916_mss}, { .compatible = "qcom,msm8974-mss-pil", .data = &msm8974_mss}, { .compatible = "qcom,msm8996-mss-pil", .data = &msm8996_mss}, + { .compatible = "qcom,sdm845-mss-pil", .data = &sdm845_mss}, { }, }; MODULE_DEVICE_TABLE(of, q6v5_of_match); diff --git a/drivers/reset/reset-ti-syscon.c b/drivers/reset/reset-ti-syscon.c index 99520b0a1329..a2635c21db7f 100644 --- a/drivers/reset/reset-ti-syscon.c +++ b/drivers/reset/reset-ti-syscon.c @@ -189,7 +189,8 @@ static int ti_syscon_reset_probe(struct platform_device *pdev) } nr_controls = (size / sizeof(*list)) / 7; - controls = devm_kzalloc(dev, nr_controls * sizeof(*controls), GFP_KERNEL); + controls = devm_kcalloc(dev, nr_controls, sizeof(*controls), + GFP_KERNEL); if (!controls) return -ENOMEM; diff --git a/drivers/reset/reset-uniphier.c b/drivers/reset/reset-uniphier.c index ac18f2f27881..e9030ff1bf2f 100644 --- a/drivers/reset/reset-uniphier.c +++ b/drivers/reset/reset-uniphier.c @@ -63,6 +63,9 @@ static const struct uniphier_reset_data uniphier_pro4_sys_reset_data[] = { UNIPHIER_RESETX(12, 0x2000, 6), /* GIO (Ether, SATA, USB3) */ UNIPHIER_RESETX(14, 0x2000, 17), /* USB30 */ UNIPHIER_RESETX(15, 0x2004, 17), /* USB31 */ + UNIPHIER_RESETX(28, 0x2000, 18), /* SATA0 */ + UNIPHIER_RESETX(29, 0x2004, 18), /* SATA1 */ + UNIPHIER_RESETX(30, 0x2000, 19), /* SATA-PHY */ UNIPHIER_RESETX(40, 0x2000, 13), /* AIO */ UNIPHIER_RESET_END, }; @@ -73,6 +76,7 @@ static const struct uniphier_reset_data uniphier_pro5_sys_reset_data[] = { UNIPHIER_RESETX(12, 0x2000, 6), /* GIO (PCIe, USB3) */ UNIPHIER_RESETX(14, 0x2000, 17), /* USB30 */ UNIPHIER_RESETX(15, 0x2004, 17), /* USB31 */ + UNIPHIER_RESETX(24, 0x2008, 2), /* PCIe */ UNIPHIER_RESETX(40, 0x2000, 13), /* AIO */ UNIPHIER_RESET_END, }; @@ -89,7 +93,7 @@ static const struct uniphier_reset_data uniphier_pxs2_sys_reset_data[] = { UNIPHIER_RESETX(20, 0x2014, 5), /* USB31-PHY0 */ UNIPHIER_RESETX(21, 0x2014, 1), /* USB31-PHY1 */ UNIPHIER_RESETX(28, 0x2014, 12), /* SATA */ - UNIPHIER_RESET(29, 0x2014, 8), /* SATA-PHY (active high) */ + UNIPHIER_RESET(30, 0x2014, 8), /* SATA-PHY (active high) */ UNIPHIER_RESETX(40, 0x2000, 13), /* AIO */ UNIPHIER_RESET_END, }; @@ -99,6 +103,7 @@ static const struct uniphier_reset_data uniphier_ld11_sys_reset_data[] = { UNIPHIER_RESETX(4, 0x200c, 2), /* eMMC */ UNIPHIER_RESETX(6, 0x200c, 6), /* Ether */ UNIPHIER_RESETX(8, 0x200c, 8), /* STDMAC (HSC, MIO) */ + UNIPHIER_RESETX(9, 0x200c, 9), /* HSC */ UNIPHIER_RESETX(40, 0x2008, 0), /* AIO */ UNIPHIER_RESETX(41, 0x2008, 1), /* EVEA */ UNIPHIER_RESETX(42, 0x2010, 2), /* EXIV */ @@ -110,11 +115,13 @@ static const struct uniphier_reset_data uniphier_ld20_sys_reset_data[] = { UNIPHIER_RESETX(4, 0x200c, 2), /* eMMC */ UNIPHIER_RESETX(6, 0x200c, 6), /* Ether */ UNIPHIER_RESETX(8, 0x200c, 8), /* STDMAC (HSC) */ + UNIPHIER_RESETX(9, 0x200c, 9), /* HSC */ UNIPHIER_RESETX(14, 0x200c, 5), /* USB30 */ UNIPHIER_RESETX(16, 0x200c, 12), /* USB30-PHY0 */ UNIPHIER_RESETX(17, 0x200c, 13), /* USB30-PHY1 */ UNIPHIER_RESETX(18, 0x200c, 14), /* USB30-PHY2 */ UNIPHIER_RESETX(19, 0x200c, 15), /* USB30-PHY3 */ + UNIPHIER_RESETX(24, 0x200c, 4), /* PCIe */ UNIPHIER_RESETX(40, 0x2008, 0), /* AIO */ UNIPHIER_RESETX(41, 0x2008, 1), /* EVEA */ UNIPHIER_RESETX(42, 0x2010, 2), /* EXIV */ @@ -134,6 +141,10 @@ static const struct uniphier_reset_data uniphier_pxs3_sys_reset_data[] = { UNIPHIER_RESETX(18, 0x200c, 20), /* USB30-PHY2 */ UNIPHIER_RESETX(20, 0x200c, 17), /* USB31-PHY0 */ UNIPHIER_RESETX(21, 0x200c, 19), /* USB31-PHY1 */ + UNIPHIER_RESETX(24, 0x200c, 3), /* PCIe */ + UNIPHIER_RESETX(28, 0x200c, 7), /* SATA0 */ + UNIPHIER_RESETX(29, 0x200c, 8), /* SATA1 */ + UNIPHIER_RESETX(30, 0x200c, 21), /* SATA-PHY */ UNIPHIER_RESET_END, }; diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig index 65a9f6b892f0..d0322b41eca5 100644 --- a/drivers/rpmsg/Kconfig +++ b/drivers/rpmsg/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + menu "Rpmsg drivers" # RPMSG always gets selected by whoever wants it @@ -39,6 +41,7 @@ config RPMSG_QCOM_GLINK_SMEM config RPMSG_QCOM_SMD tristate "Qualcomm Shared Memory Driver (SMD)" + depends on MAILBOX depends on QCOM_SMEM select RPMSG help diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 768ef542a841..f505f58b797d 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -1,14 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2016-2017, Linaro Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/idr.h> diff --git a/drivers/rpmsg/qcom_glink_native.h b/drivers/rpmsg/qcom_glink_native.h index 0cae8a8199f8..624184fc458e 100644 --- a/drivers/rpmsg/qcom_glink_native.h +++ b/drivers/rpmsg/qcom_glink_native.h @@ -1,14 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2016-2017, Linaro Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __QCOM_GLINK_NATIVE_H__ diff --git a/drivers/rpmsg/qcom_glink_rpm.c b/drivers/rpmsg/qcom_glink_rpm.c index 69b25d157d0f..f64f45d1a735 100644 --- a/drivers/rpmsg/qcom_glink_rpm.c +++ b/drivers/rpmsg/qcom_glink_rpm.c @@ -1,14 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2016-2017, Linaro Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/idr.h> diff --git a/drivers/rpmsg/qcom_glink_smem.c b/drivers/rpmsg/qcom_glink_smem.c index 3fa9d43e2c87..2b5cf2790954 100644 --- a/drivers/rpmsg/qcom_glink_smem.c +++ b/drivers/rpmsg/qcom_glink_smem.c @@ -1,14 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2016, Linaro Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/io.h> diff --git a/drivers/rpmsg/qcom_smd.c b/drivers/rpmsg/qcom_smd.c index 5ce9bf7b897d..6437bbeebc91 100644 --- a/drivers/rpmsg/qcom_smd.c +++ b/drivers/rpmsg/qcom_smd.c @@ -1,19 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2015, Sony Mobile Communications AB. * Copyright (c) 2012-2013, The Linux Foundation. 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 version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/interrupt.h> #include <linux/io.h> +#include <linux/mailbox_client.h> #include <linux/mfd/syscon.h> #include <linux/module.h> #include <linux/of_irq.h> @@ -107,6 +100,8 @@ static const struct { * @ipc_regmap: regmap handle holding the outgoing ipc register * @ipc_offset: offset within @ipc_regmap of the register for ipc * @ipc_bit: bit in the register at @ipc_offset of @ipc_regmap + * @mbox_client: mailbox client handle + * @mbox_chan: apcs ipc mailbox channel handle * @channels: list of all channels detected on this edge * @channels_lock: guard for modifications of @channels * @allocated: array of bitmaps representing already allocated channels @@ -129,6 +124,9 @@ struct qcom_smd_edge { int ipc_offset; int ipc_bit; + struct mbox_client mbox_client; + struct mbox_chan *mbox_chan; + struct list_head channels; spinlock_t channels_lock; @@ -366,7 +364,17 @@ static void qcom_smd_signal_channel(struct qcom_smd_channel *channel) { struct qcom_smd_edge *edge = channel->edge; - regmap_write(edge->ipc_regmap, edge->ipc_offset, BIT(edge->ipc_bit)); + if (edge->mbox_chan) { + /* + * We can ignore a failing mbox_send_message() as the only + * possible cause is that the FIFO in the framework is full of + * other writes to the same bit. + */ + mbox_send_message(edge->mbox_chan, NULL); + mbox_client_txdone(edge->mbox_chan, 0); + } else { + regmap_write(edge->ipc_regmap, edge->ipc_offset, BIT(edge->ipc_bit)); + } } /* @@ -1100,12 +1108,12 @@ static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *ed void *info; int ret; - channel = devm_kzalloc(&edge->dev, sizeof(*channel), GFP_KERNEL); + channel = kzalloc(sizeof(*channel), GFP_KERNEL); if (!channel) return ERR_PTR(-ENOMEM); channel->edge = edge; - channel->name = devm_kstrdup(&edge->dev, name, GFP_KERNEL); + channel->name = kstrdup(name, GFP_KERNEL); if (!channel->name) return ERR_PTR(-ENOMEM); @@ -1156,8 +1164,8 @@ static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *ed return channel; free_name_and_channel: - devm_kfree(&edge->dev, channel->name); - devm_kfree(&edge->dev, channel); + kfree(channel->name); + kfree(channel); return ERR_PTR(ret); } @@ -1326,27 +1334,37 @@ static int qcom_smd_parse_edge(struct device *dev, key = "qcom,remote-pid"; of_property_read_u32(node, key, &edge->remote_pid); - syscon_np = of_parse_phandle(node, "qcom,ipc", 0); - if (!syscon_np) { - dev_err(dev, "no qcom,ipc node\n"); - return -ENODEV; - } + edge->mbox_client.dev = dev; + edge->mbox_client.knows_txdone = true; + edge->mbox_chan = mbox_request_channel(&edge->mbox_client, 0); + if (IS_ERR(edge->mbox_chan)) { + if (PTR_ERR(edge->mbox_chan) != -ENODEV) + return PTR_ERR(edge->mbox_chan); - edge->ipc_regmap = syscon_node_to_regmap(syscon_np); - if (IS_ERR(edge->ipc_regmap)) - return PTR_ERR(edge->ipc_regmap); + edge->mbox_chan = NULL; - key = "qcom,ipc"; - ret = of_property_read_u32_index(node, key, 1, &edge->ipc_offset); - if (ret < 0) { - dev_err(dev, "no offset in %s\n", key); - return -EINVAL; - } + syscon_np = of_parse_phandle(node, "qcom,ipc", 0); + if (!syscon_np) { + dev_err(dev, "no qcom,ipc node\n"); + return -ENODEV; + } - ret = of_property_read_u32_index(node, key, 2, &edge->ipc_bit); - if (ret < 0) { - dev_err(dev, "no bit in %s\n", key); - return -EINVAL; + edge->ipc_regmap = syscon_node_to_regmap(syscon_np); + if (IS_ERR(edge->ipc_regmap)) + return PTR_ERR(edge->ipc_regmap); + + key = "qcom,ipc"; + ret = of_property_read_u32_index(node, key, 1, &edge->ipc_offset); + if (ret < 0) { + dev_err(dev, "no offset in %s\n", key); + return -EINVAL; + } + + ret = of_property_read_u32_index(node, key, 2, &edge->ipc_bit); + if (ret < 0) { + dev_err(dev, "no bit in %s\n", key); + return -EINVAL; + } } ret = of_property_read_string(node, "label", &edge->name); @@ -1378,13 +1396,13 @@ static int qcom_smd_parse_edge(struct device *dev, */ static void qcom_smd_edge_release(struct device *dev) { - struct qcom_smd_channel *channel; + struct qcom_smd_channel *channel, *tmp; struct qcom_smd_edge *edge = to_smd_edge(dev); - list_for_each_entry(channel, &edge->channels, list) { - SET_RX_CHANNEL_INFO(channel, state, SMD_CHANNEL_CLOSED); - SET_RX_CHANNEL_INFO(channel, head, 0); - SET_RX_CHANNEL_INFO(channel, tail, 0); + list_for_each_entry_safe(channel, tmp, &edge->channels, list) { + list_del(&channel->list); + kfree(channel->name); + kfree(channel); } kfree(edge); @@ -1453,6 +1471,9 @@ struct qcom_smd_edge *qcom_smd_register_edge(struct device *parent, return edge; unregister_dev: + if (!IS_ERR_OR_NULL(edge->mbox_chan)) + mbox_free_channel(edge->mbox_chan); + device_unregister(&edge->dev); return ERR_PTR(ret); } @@ -1481,6 +1502,7 @@ int qcom_smd_unregister_edge(struct qcom_smd_edge *edge) if (ret) dev_warn(&edge->dev, "can't remove smd device: %d\n", ret); + mbox_free_channel(edge->mbox_chan); device_unregister(&edge->dev); return 0; diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c index 1efdf9ff8679..76a4477c6364 100644 --- a/drivers/rpmsg/rpmsg_char.c +++ b/drivers/rpmsg/rpmsg_char.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2016, Linaro Ltd. * Copyright (c) 2012, Michal Simek <monstr@monstr.eu> @@ -7,15 +8,6 @@ * * Based on rpmsg performance statistics driver by Michal Simek, which in turn * was based on TI & Google OMX rpmsg driver. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/cdev.h> #include <linux/device.h> diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c index 920a02f0462c..b714a543a91d 100644 --- a/drivers/rpmsg/rpmsg_core.c +++ b/drivers/rpmsg/rpmsg_core.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * remote processor messaging bus * @@ -6,15 +7,6 @@ * * Ohad Ben-Cohen <ohad@wizery.com> * Brian Swetland <swetland@google.com> - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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. */ #define pr_fmt(fmt) "%s: " fmt, __func__ @@ -333,11 +325,49 @@ field##_show(struct device *dev, \ } \ static DEVICE_ATTR_RO(field); +#define rpmsg_string_attr(field, member) \ +static ssize_t \ +field##_store(struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t sz) \ +{ \ + struct rpmsg_device *rpdev = to_rpmsg_device(dev); \ + char *new, *old; \ + \ + new = kstrndup(buf, sz, GFP_KERNEL); \ + if (!new) \ + return -ENOMEM; \ + new[strcspn(new, "\n")] = '\0'; \ + \ + device_lock(dev); \ + old = rpdev->member; \ + if (strlen(new)) { \ + rpdev->member = new; \ + } else { \ + kfree(new); \ + rpdev->member = NULL; \ + } \ + device_unlock(dev); \ + \ + kfree(old); \ + \ + return sz; \ +} \ +static ssize_t \ +field##_show(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct rpmsg_device *rpdev = to_rpmsg_device(dev); \ + \ + return sprintf(buf, "%s\n", rpdev->member); \ +} \ +static DEVICE_ATTR_RW(field) + /* for more info, see Documentation/ABI/testing/sysfs-bus-rpmsg */ rpmsg_show_attr(name, id.name, "%s\n"); rpmsg_show_attr(src, src, "0x%x\n"); rpmsg_show_attr(dst, dst, "0x%x\n"); rpmsg_show_attr(announce, announce ? "true" : "false", "%s\n"); +rpmsg_string_attr(driver_override, driver_override); static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -359,6 +389,7 @@ static struct attribute *rpmsg_dev_attrs[] = { &dev_attr_dst.attr, &dev_attr_src.attr, &dev_attr_announce.attr, + &dev_attr_driver_override.attr, NULL, }; ATTRIBUTE_GROUPS(rpmsg_dev); diff --git a/drivers/rpmsg/rpmsg_internal.h b/drivers/rpmsg/rpmsg_internal.h index 685aa70e9cbe..0d791c30b7ea 100644 --- a/drivers/rpmsg/rpmsg_internal.h +++ b/drivers/rpmsg/rpmsg_internal.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * remote processor messaging bus internals * @@ -6,15 +7,6 @@ * * Ohad Ben-Cohen <ohad@wizery.com> * Brian Swetland <swetland@google.com> - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __RPMSG_INTERNAL_H__ diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c index 82b83002fcba..664f957012cd 100644 --- a/drivers/rpmsg/virtio_rpmsg_bus.c +++ b/drivers/rpmsg/virtio_rpmsg_bus.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Virtio-based remote processor messaging bus * @@ -6,15 +7,6 @@ * * Ohad Ben-Cohen <ohad@wizery.com> * Brian Swetland <swetland@google.com> - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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. */ #define pr_fmt(fmt) "%s: " fmt, __func__ diff --git a/drivers/rtc/rtc-mt6397.c b/drivers/rtc/rtc-mt6397.c index 1a61fa56f3ad..385f8303bb41 100644 --- a/drivers/rtc/rtc-mt6397.c +++ b/drivers/rtc/rtc-mt6397.c @@ -322,10 +322,9 @@ static int mtk_rtc_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); rtc->addr_base = res->start; - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - rtc->irq = irq_create_mapping(mt6397_chip->irq_domain, res->start); - if (rtc->irq <= 0) - return -EINVAL; + rtc->irq = platform_get_irq(pdev, 0); + if (rtc->irq < 0) + return rtc->irq; rtc->regmap = mt6397_chip->regmap; rtc->dev = &pdev->dev; diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c index fb2c3599d95c..0af8c5295b65 100644 --- a/drivers/s390/block/dasd_eer.c +++ b/drivers/s390/block/dasd_eer.c @@ -561,8 +561,8 @@ static int dasd_eer_open(struct inode *inp, struct file *filp) return -EINVAL; } eerb->buffersize = eerb->buffer_page_count * PAGE_SIZE; - eerb->buffer = kmalloc(eerb->buffer_page_count * sizeof(char *), - GFP_KERNEL); + eerb->buffer = kmalloc_array(eerb->buffer_page_count, sizeof(char *), + GFP_KERNEL); if (!eerb->buffer) { kfree(eerb); return -ENOMEM; diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 29024492b8ed..ed607288e696 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -238,9 +238,9 @@ dcssblk_is_continuous(struct dcssblk_dev_info *dev_info) if (dev_info->num_of_segments <= 1) return 0; - sort_list = kzalloc( - sizeof(struct segment_info) * dev_info->num_of_segments, - GFP_KERNEL); + sort_list = kcalloc(dev_info->num_of_segments, + sizeof(struct segment_info), + GFP_KERNEL); if (sort_list == NULL) return -ENOMEM; i = 0; diff --git a/drivers/s390/char/keyboard.c b/drivers/s390/char/keyboard.c index db1fbf9b00b5..79eb60958015 100644 --- a/drivers/s390/char/keyboard.c +++ b/drivers/s390/char/keyboard.c @@ -78,7 +78,7 @@ kbd_alloc(void) { } } kbd->fn_handler = - kzalloc(sizeof(fn_handler_fn *) * NR_FN_HANDLER, GFP_KERNEL); + kcalloc(NR_FN_HANDLER, sizeof(fn_handler_fn *), GFP_KERNEL); if (!kbd->fn_handler) goto out_func; kbd->accent_table = kmemdup(ebc_accent_table, diff --git a/drivers/s390/char/sclp_sd.c b/drivers/s390/char/sclp_sd.c index 99f41db5123b..1e244f78f192 100644 --- a/drivers/s390/char/sclp_sd.c +++ b/drivers/s390/char/sclp_sd.c @@ -300,7 +300,7 @@ static int sclp_sd_store_data(struct sclp_sd_data *result, u8 di) goto out_result; /* Allocate memory */ - data = vzalloc((size_t) dsize * PAGE_SIZE); + data = vzalloc(array_size((size_t)dsize, PAGE_SIZE)); if (!data) { rc = -ENOMEM; goto out; diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index 1c98023cffd4..5b8af2782282 100644 --- a/drivers/s390/char/tty3270.c +++ b/drivers/s390/char/tty3270.c @@ -719,7 +719,8 @@ tty3270_alloc_view(void) if (!tp) goto out_err; tp->freemem_pages = - kmalloc(sizeof(void *) * TTY3270_STRING_PAGES, GFP_KERNEL); + kmalloc_array(TTY3270_STRING_PAGES, sizeof(void *), + GFP_KERNEL); if (!tp->freemem_pages) goto out_tp; INIT_LIST_HEAD(&tp->freemem); diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c index 52aa89424318..cbde65ab2170 100644 --- a/drivers/s390/char/vmur.c +++ b/drivers/s390/char/vmur.c @@ -242,7 +242,7 @@ static struct ccw1 *alloc_chan_prog(const char __user *ubuf, int rec_count, * That means we allocate room for CCWs to cover count/reclen * records plus a NOP. */ - cpa = kzalloc((rec_count + 1) * sizeof(struct ccw1), + cpa = kcalloc(rec_count + 1, sizeof(struct ccw1), GFP_KERNEL | GFP_DMA); if (!cpa) return ERR_PTR(-ENOMEM); diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index 4369662cfff5..76d3c50bf078 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c @@ -152,7 +152,7 @@ static int zcore_memmap_open(struct inode *inode, struct file *filp) char *buf; int i = 0; - buf = kzalloc(memblock.memory.cnt * CHUNK_INFO_SIZE, GFP_KERNEL); + buf = kcalloc(memblock.memory.cnt, CHUNK_INFO_SIZE, GFP_KERNEL); if (!buf) { return -ENOMEM; } diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index 4c14ce428e92..78f1be41b05e 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c @@ -536,7 +536,7 @@ void qdio_print_subchannel_info(struct qdio_irq *irq_ptr, int qdio_enable_async_operation(struct qdio_output_q *outq) { - outq->aobs = kzalloc(sizeof(struct qaob *) * QDIO_MAX_BUFFERS_PER_Q, + outq->aobs = kcalloc(QDIO_MAX_BUFFERS_PER_Q, sizeof(struct qaob *), GFP_ATOMIC); if (!outq->aobs) { outq->use_cq = 0; diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c index 0787b587e4b8..07dea602205b 100644 --- a/drivers/s390/cio/qdio_thinint.c +++ b/drivers/s390/cio/qdio_thinint.c @@ -241,8 +241,9 @@ out: /* allocate non-shared indicators and shared indicator */ int __init tiqdio_allocate_memory(void) { - q_indicators = kzalloc(sizeof(struct indicator_t) * TIQDIO_NR_INDICATORS, - GFP_KERNEL); + q_indicators = kcalloc(TIQDIO_NR_INDICATORS, + sizeof(struct indicator_t), + GFP_KERNEL); if (!q_indicators) return -ENOMEM; return 0; diff --git a/drivers/s390/crypto/pkey_api.c b/drivers/s390/crypto/pkey_api.c index ed80d00cdb6f..3929c8be8098 100644 --- a/drivers/s390/crypto/pkey_api.c +++ b/drivers/s390/crypto/pkey_api.c @@ -121,7 +121,7 @@ static int alloc_and_prep_cprbmem(size_t paramblen, * allocate consecutive memory for request CPRB, request param * block, reply CPRB and reply param block */ - cprbmem = kzalloc(2 * cprbplusparamblen, GFP_KERNEL); + cprbmem = kcalloc(2, cprbplusparamblen, GFP_KERNEL); if (!cprbmem) return -ENOMEM; @@ -899,9 +899,9 @@ int pkey_findcard(const struct pkey_seckey *seckey, return -EINVAL; /* fetch status of all crypto cards */ - device_status = kmalloc(MAX_ZDEV_ENTRIES_EXT - * sizeof(struct zcrypt_device_status_ext), - GFP_KERNEL); + device_status = kmalloc_array(MAX_ZDEV_ENTRIES_EXT, + sizeof(struct zcrypt_device_status_ext), + GFP_KERNEL); if (!device_status) return -ENOMEM; zcrypt_device_status_mask_ext(device_status); diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index 7ce98b70cad3..7617d21cb296 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c @@ -1379,7 +1379,7 @@ static int add_channel(struct ccw_device *cdev, enum ctcm_channel_types type, } else ccw_num = 8; - ch->ccw = kzalloc(ccw_num * sizeof(struct ccw1), GFP_KERNEL | GFP_DMA); + ch->ccw = kcalloc(ccw_num, sizeof(struct ccw1), GFP_KERNEL | GFP_DMA); if (ch->ccw == NULL) goto nomem_return; diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 9f28b6f2efc4..8e1474f1ffac 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -374,9 +374,10 @@ static int qeth_alloc_cq(struct qeth_card *card) } card->qdio.no_in_queues = 2; card->qdio.out_bufstates = - kzalloc(card->qdio.no_out_queues * - QDIO_MAX_BUFFERS_PER_Q * - sizeof(struct qdio_outbuf_state), GFP_KERNEL); + kcalloc(card->qdio.no_out_queues * + QDIO_MAX_BUFFERS_PER_Q, + sizeof(struct qdio_outbuf_state), + GFP_KERNEL); outbuf_states = card->qdio.out_bufstates; if (outbuf_states == NULL) { rc = -1; @@ -2538,8 +2539,9 @@ static int qeth_alloc_qdio_buffers(struct qeth_card *card) /* outbound */ card->qdio.out_qs = - kzalloc(card->qdio.no_out_queues * - sizeof(struct qeth_qdio_out_q *), GFP_KERNEL); + kcalloc(card->qdio.no_out_queues, + sizeof(struct qeth_qdio_out_q *), + GFP_KERNEL); if (!card->qdio.out_qs) goto out_freepool; for (i = 0; i < card->qdio.no_out_queues; ++i) { @@ -4963,8 +4965,8 @@ static int qeth_qdio_establish(struct qeth_card *card) QETH_DBF_TEXT(SETUP, 2, "qdioest"); - qib_param_field = kzalloc(QDIO_MAX_BUFFERS_PER_Q * sizeof(char), - GFP_KERNEL); + qib_param_field = kzalloc(QDIO_MAX_BUFFERS_PER_Q, + GFP_KERNEL); if (!qib_param_field) { rc = -ENOMEM; goto out_free_nothing; @@ -4973,8 +4975,8 @@ static int qeth_qdio_establish(struct qeth_card *card) qeth_create_qib_param_field(card, qib_param_field); qeth_create_qib_param_field_blkt(card, qib_param_field); - in_sbal_ptrs = kzalloc(card->qdio.no_in_queues * - QDIO_MAX_BUFFERS_PER_Q * sizeof(void *), + in_sbal_ptrs = kcalloc(card->qdio.no_in_queues * QDIO_MAX_BUFFERS_PER_Q, + sizeof(void *), GFP_KERNEL); if (!in_sbal_ptrs) { rc = -ENOMEM; @@ -4985,7 +4987,7 @@ static int qeth_qdio_establish(struct qeth_card *card) virt_to_phys(card->qdio.in_q->bufs[i].buffer); } - queue_start_poll = kzalloc(sizeof(void *) * card->qdio.no_in_queues, + queue_start_poll = kcalloc(card->qdio.no_in_queues, sizeof(void *), GFP_KERNEL); if (!queue_start_poll) { rc = -ENOMEM; @@ -4997,8 +4999,9 @@ static int qeth_qdio_establish(struct qeth_card *card) qeth_qdio_establish_cq(card, in_sbal_ptrs, queue_start_poll); out_sbal_ptrs = - kzalloc(card->qdio.no_out_queues * QDIO_MAX_BUFFERS_PER_Q * - sizeof(void *), GFP_KERNEL); + kcalloc(card->qdio.no_out_queues * QDIO_MAX_BUFFERS_PER_Q, + sizeof(void *), + GFP_KERNEL); if (!out_sbal_ptrs) { rc = -ENOMEM; goto out_free_queue_start_poll; diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c index 35380a58d3f0..0d4ffe0ae306 100644 --- a/drivers/scsi/BusLogic.c +++ b/drivers/scsi/BusLogic.c @@ -2366,7 +2366,7 @@ static int __init blogic_init(void) if (blogic_probe_options.noprobe) return -ENODEV; blogic_probeinfo_list = - kzalloc(BLOGIC_MAX_ADAPTERS * sizeof(struct blogic_probeinfo), + kcalloc(BLOGIC_MAX_ADAPTERS, sizeof(struct blogic_probeinfo), GFP_KERNEL); if (blogic_probeinfo_list == NULL) { blogic_err("BusLogic: Unable to allocate Probe Info List\n", diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index e7961cbd2c55..a9831bd37a73 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -4132,7 +4132,7 @@ static int aac_convert_sgraw2(struct aac_raw_io2 *rio2, int pages, int nseg, int if (aac_convert_sgl == 0) return 0; - sge = kmalloc(nseg_new * sizeof(struct sge_ieee1212), GFP_ATOMIC); + sge = kmalloc_array(nseg_new, sizeof(struct sge_ieee1212), GFP_ATOMIC); if (sge == NULL) return -ENOMEM; diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c index a2b3430072c7..25f6600d6c09 100644 --- a/drivers/scsi/aacraid/commctrl.c +++ b/drivers/scsi/aacraid/commctrl.c @@ -845,7 +845,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) rcode = -EINVAL; goto cleanup; } - p = kmalloc(sg_count[i], GFP_KERNEL|GFP_DMA32); + p = kmalloc(sg_count[i], GFP_KERNEL); if (!p) { dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", sg_count[i], i, usg->count)); @@ -886,7 +886,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) rcode = -EINVAL; goto cleanup; } - p = kmalloc(sg_count[i], GFP_KERNEL|GFP_DMA32); + p = kmalloc(sg_count[i], GFP_KERNEL); if (!p) { dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", sg_count[i], i, upsg->count)); diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index f24fb942065d..04443577d48b 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -1681,7 +1681,9 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) if (aac_reset_devices || reset_devices) aac->init_reset = true; - aac->fibs = kzalloc(sizeof(struct fib) * (shost->can_queue + AAC_NUM_MGT_FIB), GFP_KERNEL); + aac->fibs = kcalloc(shost->can_queue + AAC_NUM_MGT_FIB, + sizeof(struct fib), + GFP_KERNEL); if (!aac->fibs) goto out_free_host; spin_lock_init(&aac->fib_lock); diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c index 124217927c4a..41add33e3f1f 100644 --- a/drivers/scsi/aha1542.c +++ b/drivers/scsi/aha1542.c @@ -400,7 +400,8 @@ static int aha1542_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd) #endif if (bufflen) { /* allocate memory before taking host_lock */ sg_count = scsi_sg_count(cmd); - cptr = kmalloc(sizeof(*cptr) * sg_count, GFP_KERNEL | GFP_DMA); + cptr = kmalloc_array(sg_count, sizeof(*cptr), + GFP_KERNEL | GFP_DMA); if (!cptr) return SCSI_MLQUEUE_HOST_BUSY; } else { diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c index 034f4eebb160..2d82ec85753e 100644 --- a/drivers/scsi/aic7xxx/aic79xx_core.c +++ b/drivers/scsi/aic7xxx/aic79xx_core.c @@ -6112,10 +6112,6 @@ ahd_alloc(void *platform_arg, char *name) ahd->int_coalescing_stop_threshold = AHD_INT_COALESCING_STOP_THRESHOLD_DEFAULT; - if (ahd_platform_alloc(ahd, platform_arg) != 0) { - ahd_free(ahd); - ahd = NULL; - } #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MEMORY) != 0) { printk("%s: scb size = 0x%x, hscb size = 0x%x\n", @@ -6123,6 +6119,10 @@ ahd_alloc(void *platform_arg, char *name) (u_int)sizeof(struct hardware_scb)); } #endif + if (ahd_platform_alloc(ahd, platform_arg) != 0) { + ahd_free(ahd); + ahd = NULL; + } return (ahd); } @@ -7063,7 +7063,8 @@ ahd_init(struct ahd_softc *ahd) AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); ahd->stack_size = ahd_probe_stack_size(ahd); - ahd->saved_stack = kmalloc(ahd->stack_size * sizeof(uint16_t), GFP_ATOMIC); + ahd->saved_stack = kmalloc_array(ahd->stack_size, sizeof(uint16_t), + GFP_ATOMIC); if (ahd->saved_stack == NULL) return (ENOMEM); diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c index e97eceacf522..915a34f141e4 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_core.c +++ b/drivers/scsi/aic7xxx/aic7xxx_core.c @@ -4779,8 +4779,8 @@ ahc_init_scbdata(struct ahc_softc *ahc) SLIST_INIT(&scb_data->sg_maps); /* Allocate SCB resources */ - scb_data->scbarray = kzalloc(sizeof(struct scb) * AHC_SCB_MAX_ALLOC, - GFP_ATOMIC); + scb_data->scbarray = kcalloc(AHC_SCB_MAX_ALLOC, sizeof(struct scb), + GFP_ATOMIC); if (scb_data->scbarray == NULL) return (ENOMEM); diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.c b/drivers/scsi/aic94xx/aic94xx_hwi.c index 2dbc8330d7d3..3b8ad55e59de 100644 --- a/drivers/scsi/aic94xx/aic94xx_hwi.c +++ b/drivers/scsi/aic94xx/aic94xx_hwi.c @@ -220,8 +220,9 @@ static int asd_init_scbs(struct asd_ha_struct *asd_ha) /* allocate the index array and bitmap */ asd_ha->seq.tc_index_bitmap_bits = asd_ha->hw_prof.max_scbs; - asd_ha->seq.tc_index_array = kzalloc(asd_ha->seq.tc_index_bitmap_bits* - sizeof(void *), GFP_KERNEL); + asd_ha->seq.tc_index_array = kcalloc(asd_ha->seq.tc_index_bitmap_bits, + sizeof(void *), + GFP_KERNEL); if (!asd_ha->seq.tc_index_array) return -ENOMEM; @@ -291,7 +292,8 @@ static int asd_alloc_edbs(struct asd_ha_struct *asd_ha, gfp_t gfp_flags) struct asd_seq_data *seq = &asd_ha->seq; int i; - seq->edb_arr = kmalloc(seq->num_edbs*sizeof(*seq->edb_arr), gfp_flags); + seq->edb_arr = kmalloc_array(seq->num_edbs, sizeof(*seq->edb_arr), + gfp_flags); if (!seq->edb_arr) return -ENOMEM; @@ -323,8 +325,8 @@ static int asd_alloc_escbs(struct asd_ha_struct *asd_ha, struct asd_ascb *escb; int i, escbs; - seq->escb_arr = kmalloc(seq->num_escbs*sizeof(*seq->escb_arr), - gfp_flags); + seq->escb_arr = kmalloc_array(seq->num_escbs, sizeof(*seq->escb_arr), + gfp_flags); if (!seq->escb_arr) return -ENOMEM; diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c index 6c838865ac5a..80e5b283fd81 100644 --- a/drivers/scsi/aic94xx/aic94xx_init.c +++ b/drivers/scsi/aic94xx/aic94xx_init.c @@ -350,7 +350,7 @@ static ssize_t asd_store_update_bios(struct device *dev, int flash_command = FLASH_CMD_NONE; int err = 0; - cmd_ptr = kzalloc(count*2, GFP_KERNEL); + cmd_ptr = kcalloc(count, 2, GFP_KERNEL); if (!cmd_ptr) { err = FAIL_OUT_MEMORY; diff --git a/drivers/scsi/arm/queue.c b/drivers/scsi/arm/queue.c index 3441ce3ebabf..996dfe903928 100644 --- a/drivers/scsi/arm/queue.c +++ b/drivers/scsi/arm/queue.c @@ -70,7 +70,7 @@ int queue_initialise (Queue_t *queue) * need to keep free lists or allocate this * memory. */ - queue->alloc = q = kmalloc(sizeof(QE_t) * nqueues, GFP_KERNEL); + queue->alloc = q = kmalloc_array(nqueues, sizeof(QE_t), GFP_KERNEL); if (q) { for (; nqueues; q++, nqueues--) { SET_MAGIC(q, QUEUE_MAGIC_FREE); diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index b3cfdd5f4d1c..818d185d63f0 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -2467,8 +2467,8 @@ static int beiscsi_alloc_mem(struct beiscsi_hba *phba) /* Allocate memory for wrb_context */ phwi_ctrlr = phba->phwi_ctrlr; - phwi_ctrlr->wrb_context = kzalloc(sizeof(struct hwi_wrb_context) * - phba->params.cxns_per_ctrl, + phwi_ctrlr->wrb_context = kcalloc(phba->params.cxns_per_ctrl, + sizeof(struct hwi_wrb_context), GFP_KERNEL); if (!phwi_ctrlr->wrb_context) { kfree(phba->phwi_ctrlr); @@ -2483,8 +2483,9 @@ static int beiscsi_alloc_mem(struct beiscsi_hba *phba) return -ENOMEM; } - mem_arr_orig = kmalloc(sizeof(*mem_arr_orig) * BEISCSI_MAX_FRAGS_INIT, - GFP_KERNEL); + mem_arr_orig = kmalloc_array(BEISCSI_MAX_FRAGS_INIT, + sizeof(*mem_arr_orig), + GFP_KERNEL); if (!mem_arr_orig) { kfree(phba->init_mem); kfree(phwi_ctrlr->wrb_context); @@ -2533,8 +2534,8 @@ static int beiscsi_alloc_mem(struct beiscsi_hba *phba) } while (alloc_size); mem_descr->num_elements = j; mem_descr->size_in_bytes = phba->mem_req[i]; - mem_descr->mem_array = kmalloc(sizeof(*mem_arr) * j, - GFP_KERNEL); + mem_descr->mem_array = kmalloc_array(j, sizeof(*mem_arr), + GFP_KERNEL); if (!mem_descr->mem_array) goto free_mem; @@ -2620,8 +2621,8 @@ static int beiscsi_init_wrb_handle(struct beiscsi_hba *phba) /* Allocate memory for WRBQ */ phwi_ctxt = phwi_ctrlr->phwi_ctxt; - phwi_ctxt->be_wrbq = kzalloc(sizeof(struct be_queue_info) * - phba->params.cxns_per_ctrl, + phwi_ctxt->be_wrbq = kcalloc(phba->params.cxns_per_ctrl, + sizeof(struct be_queue_info), GFP_KERNEL); if (!phwi_ctxt->be_wrbq) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, @@ -2632,16 +2633,18 @@ static int beiscsi_init_wrb_handle(struct beiscsi_hba *phba) for (index = 0; index < phba->params.cxns_per_ctrl; index++) { pwrb_context = &phwi_ctrlr->wrb_context[index]; pwrb_context->pwrb_handle_base = - kzalloc(sizeof(struct wrb_handle *) * - phba->params.wrbs_per_cxn, GFP_KERNEL); + kcalloc(phba->params.wrbs_per_cxn, + sizeof(struct wrb_handle *), + GFP_KERNEL); if (!pwrb_context->pwrb_handle_base) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, "BM_%d : Mem Alloc Failed. Failing to load\n"); goto init_wrb_hndl_failed; } pwrb_context->pwrb_handle_basestd = - kzalloc(sizeof(struct wrb_handle *) * - phba->params.wrbs_per_cxn, GFP_KERNEL); + kcalloc(phba->params.wrbs_per_cxn, + sizeof(struct wrb_handle *), + GFP_KERNEL); if (!pwrb_context->pwrb_handle_basestd) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, "BM_%d : Mem Alloc Failed. Failing to load\n"); @@ -3353,8 +3356,9 @@ beiscsi_create_wrb_rings(struct beiscsi_hba *phba, idx = 0; mem_descr = phba->init_mem; mem_descr += HWI_MEM_WRB; - pwrb_arr = kmalloc(sizeof(*pwrb_arr) * phba->params.cxns_per_ctrl, - GFP_KERNEL); + pwrb_arr = kmalloc_array(phba->params.cxns_per_ctrl, + sizeof(*pwrb_arr), + GFP_KERNEL); if (!pwrb_arr) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, "BM_%d : Memory alloc failed in create wrb ring.\n"); @@ -3894,18 +3898,18 @@ static int beiscsi_init_sgl_handle(struct beiscsi_hba *phba) mem_descr_sglh = phba->init_mem; mem_descr_sglh += HWI_MEM_SGLH; if (1 == mem_descr_sglh->num_elements) { - phba->io_sgl_hndl_base = kzalloc(sizeof(struct sgl_handle *) * - phba->params.ios_per_ctrl, + phba->io_sgl_hndl_base = kcalloc(phba->params.ios_per_ctrl, + sizeof(struct sgl_handle *), GFP_KERNEL); if (!phba->io_sgl_hndl_base) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, "BM_%d : Mem Alloc Failed. Failing to load\n"); return -ENOMEM; } - phba->eh_sgl_hndl_base = kzalloc(sizeof(struct sgl_handle *) * - (phba->params.icds_per_ctrl - - phba->params.ios_per_ctrl), - GFP_KERNEL); + phba->eh_sgl_hndl_base = + kcalloc(phba->params.icds_per_ctrl - + phba->params.ios_per_ctrl, + sizeof(struct sgl_handle *), GFP_KERNEL); if (!phba->eh_sgl_hndl_base) { kfree(phba->io_sgl_hndl_base); beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, @@ -4032,8 +4036,9 @@ static int hba_setup_cid_tbls(struct beiscsi_hba *phba) phba->cid_array_info[ulp_num] = ptr_cid_info; } } - phba->ep_array = kzalloc(sizeof(struct iscsi_endpoint *) * - phba->params.cxns_per_ctrl, GFP_KERNEL); + phba->ep_array = kcalloc(phba->params.cxns_per_ctrl, + sizeof(struct iscsi_endpoint *), + GFP_KERNEL); if (!phba->ep_array) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, "BM_%d : Failed to allocate memory in " @@ -4043,8 +4048,9 @@ static int hba_setup_cid_tbls(struct beiscsi_hba *phba) goto free_memory; } - phba->conn_table = kzalloc(sizeof(struct beiscsi_conn *) * - phba->params.cxns_per_ctrl, GFP_KERNEL); + phba->conn_table = kcalloc(phba->params.cxns_per_ctrl, + sizeof(struct beiscsi_conn *), + GFP_KERNEL); if (!phba->conn_table) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT, "BM_%d : Failed to allocate memory in" diff --git a/drivers/scsi/bfa/bfad_attr.c b/drivers/scsi/bfa/bfad_attr.c index d4d276c757ea..26b0fa4e90b5 100644 --- a/drivers/scsi/bfa/bfad_attr.c +++ b/drivers/scsi/bfa/bfad_attr.c @@ -927,7 +927,7 @@ bfad_im_num_of_discovered_ports_show(struct device *dev, struct bfa_rport_qualifier_s *rports = NULL; unsigned long flags; - rports = kzalloc(sizeof(struct bfa_rport_qualifier_s) * nrports, + rports = kcalloc(nrports, sizeof(struct bfa_rport_qualifier_s), GFP_ATOMIC); if (rports == NULL) return snprintf(buf, PAGE_SIZE, "Failed\n"); diff --git a/drivers/scsi/bfa/bfad_bsg.c b/drivers/scsi/bfa/bfad_bsg.c index 7c884f881180..5d163ca1b366 100644 --- a/drivers/scsi/bfa/bfad_bsg.c +++ b/drivers/scsi/bfa/bfad_bsg.c @@ -3252,8 +3252,9 @@ bfad_fcxp_map_sg(struct bfad_s *bfad, void *payload_kbuf, struct bfa_sge_s *sg_table; int sge_num = 1; - buf_base = kzalloc((sizeof(struct bfad_buf_info) + - sizeof(struct bfa_sge_s)) * sge_num, GFP_KERNEL); + buf_base = kcalloc(sizeof(struct bfad_buf_info) + + sizeof(struct bfa_sge_s), + sge_num, GFP_KERNEL); if (!buf_base) return NULL; diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index 65de1d0578a1..f00045813378 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -1397,7 +1397,7 @@ static struct bnx2fc_hba *bnx2fc_hba_create(struct cnic_dev *cnic) hba->next_conn_id = 0; hba->tgt_ofld_list = - kzalloc(sizeof(struct bnx2fc_rport *) * BNX2FC_NUM_MAX_SESS, + kcalloc(BNX2FC_NUM_MAX_SESS, sizeof(struct bnx2fc_rport *), GFP_KERNEL); if (!hba->tgt_ofld_list) { printk(KERN_ERR PFX "Unable to allocate tgt offload list\n"); diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c index 5a645b8b9af1..350257c13a5b 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_io.c +++ b/drivers/scsi/bnx2fc/bnx2fc_io.c @@ -240,15 +240,15 @@ struct bnx2fc_cmd_mgr *bnx2fc_cmd_mgr_alloc(struct bnx2fc_hba *hba) return NULL; } - cmgr->free_list = kzalloc(sizeof(*cmgr->free_list) * - arr_sz, GFP_KERNEL); + cmgr->free_list = kcalloc(arr_sz, sizeof(*cmgr->free_list), + GFP_KERNEL); if (!cmgr->free_list) { printk(KERN_ERR PFX "failed to alloc free_list\n"); goto mem_err; } - cmgr->free_list_lock = kzalloc(sizeof(*cmgr->free_list_lock) * - arr_sz, GFP_KERNEL); + cmgr->free_list_lock = kcalloc(arr_sz, sizeof(*cmgr->free_list_lock), + GFP_KERNEL); if (!cmgr->free_list_lock) { printk(KERN_ERR PFX "failed to alloc free_list_lock\n"); kfree(cmgr->free_list); diff --git a/drivers/scsi/csiostor/csio_wr.c b/drivers/scsi/csiostor/csio_wr.c index c0a17789752f..faa357b62c61 100644 --- a/drivers/scsi/csiostor/csio_wr.c +++ b/drivers/scsi/csiostor/csio_wr.c @@ -276,7 +276,7 @@ csio_wr_alloc_q(struct csio_hw *hw, uint32_t qsize, uint32_t wrsize, q->un.iq.flq_idx = flq_idx; flq = wrm->q_arr[q->un.iq.flq_idx]; - flq->un.fl.bufs = kzalloc(flq->credits * + flq->un.fl.bufs = kcalloc(flq->credits, sizeof(struct csio_dma_buf), GFP_KERNEL); if (!flq->un.fl.bufs) { @@ -1579,7 +1579,7 @@ csio_wrm_init(struct csio_wrm *wrm, struct csio_hw *hw) return -EINVAL; } - wrm->q_arr = kzalloc(sizeof(struct csio_q *) * wrm->num_q, GFP_KERNEL); + wrm->q_arr = kcalloc(wrm->num_q, sizeof(struct csio_q *), GFP_KERNEL); if (!wrm->q_arr) goto err; diff --git a/drivers/scsi/esas2r/esas2r_init.c b/drivers/scsi/esas2r/esas2r_init.c index 9db645dde35e..bbe77db8938d 100644 --- a/drivers/scsi/esas2r/esas2r_init.c +++ b/drivers/scsi/esas2r/esas2r_init.c @@ -833,7 +833,7 @@ bool esas2r_init_adapter_struct(struct esas2r_adapter *a, /* allocate requests for asynchronous events */ a->first_ae_req = - kzalloc(num_ae_requests * sizeof(struct esas2r_request), + kcalloc(num_ae_requests, sizeof(struct esas2r_request), GFP_KERNEL); if (a->first_ae_req == NULL) { @@ -843,8 +843,8 @@ bool esas2r_init_adapter_struct(struct esas2r_adapter *a, } /* allocate the S/G list memory descriptors */ - a->sg_list_mds = kzalloc( - num_sg_lists * sizeof(struct esas2r_mem_desc), GFP_KERNEL); + a->sg_list_mds = kcalloc(num_sg_lists, sizeof(struct esas2r_mem_desc), + GFP_KERNEL); if (a->sg_list_mds == NULL) { esas2r_log(ESAS2R_LOG_CRIT, @@ -854,8 +854,9 @@ bool esas2r_init_adapter_struct(struct esas2r_adapter *a, /* allocate the request table */ a->req_table = - kzalloc((num_requests + num_ae_requests + - 1) * sizeof(struct esas2r_request *), GFP_KERNEL); + kcalloc(num_requests + num_ae_requests + 1, + sizeof(struct esas2r_request *), + GFP_KERNEL); if (a->req_table == NULL) { esas2r_log(ESAS2R_LOG_CRIT, diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c index 097f37de6ce9..ea23c8dffc25 100644 --- a/drivers/scsi/fcoe/fcoe_ctlr.c +++ b/drivers/scsi/fcoe/fcoe_ctlr.c @@ -1390,8 +1390,8 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip, */ num_vlink_desc = rlen / sizeof(*vp); if (num_vlink_desc) - vlink_desc_arr = kmalloc(sizeof(vp) * num_vlink_desc, - GFP_ATOMIC); + vlink_desc_arr = kmalloc_array(num_vlink_desc, sizeof(vp), + GFP_ATOMIC); if (!vlink_desc_arr) return; num_vlink_desc = 0; diff --git a/drivers/scsi/fnic/fnic_debugfs.c b/drivers/scsi/fnic/fnic_debugfs.c index 6d3e1cb4fea6..139fffa3658a 100644 --- a/drivers/scsi/fnic/fnic_debugfs.c +++ b/drivers/scsi/fnic/fnic_debugfs.c @@ -233,8 +233,8 @@ static int fnic_trace_debugfs_open(struct inode *inode, return -ENOMEM; if (*rdata_ptr == fc_trc_flag->fnic_trace) { - fnic_dbg_prt->buffer = vmalloc(3 * - (trace_max_pages * PAGE_SIZE)); + fnic_dbg_prt->buffer = vmalloc(array3_size(3, trace_max_pages, + PAGE_SIZE)); if (!fnic_dbg_prt->buffer) { kfree(fnic_dbg_prt); return -ENOMEM; @@ -244,7 +244,8 @@ static int fnic_trace_debugfs_open(struct inode *inode, fnic_dbg_prt->buffer_len = fnic_get_trace_data(fnic_dbg_prt); } else { fnic_dbg_prt->buffer = - vmalloc(3 * (fnic_fc_trace_max_pages * PAGE_SIZE)); + vmalloc(array3_size(3, fnic_fc_trace_max_pages, + PAGE_SIZE)); if (!fnic_dbg_prt->buffer) { kfree(fnic_dbg_prt); return -ENOMEM; diff --git a/drivers/scsi/fnic/fnic_trace.c b/drivers/scsi/fnic/fnic_trace.c index 98597b59c12a..8271785bdb93 100644 --- a/drivers/scsi/fnic/fnic_trace.c +++ b/drivers/scsi/fnic/fnic_trace.c @@ -477,8 +477,9 @@ int fnic_trace_buf_init(void) } memset((void *)fnic_trace_buf_p, 0, (trace_max_pages * PAGE_SIZE)); - fnic_trace_entries.page_offset = vmalloc(fnic_max_trace_entries * - sizeof(unsigned long)); + fnic_trace_entries.page_offset = + vmalloc(array_size(fnic_max_trace_entries, + sizeof(unsigned long))); if (!fnic_trace_entries.page_offset) { printk(KERN_ERR PFX "Failed to allocate memory for" " page_offset\n"); @@ -555,8 +556,9 @@ int fnic_fc_trace_init(void) fc_trace_max_entries = (fnic_fc_trace_max_pages * PAGE_SIZE)/ FC_TRC_SIZE_BYTES; - fnic_fc_ctlr_trace_buf_p = (unsigned long)vmalloc( - fnic_fc_trace_max_pages * PAGE_SIZE); + fnic_fc_ctlr_trace_buf_p = + (unsigned long)vmalloc(array_size(PAGE_SIZE, + fnic_fc_trace_max_pages)); if (!fnic_fc_ctlr_trace_buf_p) { pr_err("fnic: Failed to allocate memory for " "FC Control Trace Buf\n"); @@ -568,8 +570,9 @@ int fnic_fc_trace_init(void) fnic_fc_trace_max_pages * PAGE_SIZE); /* Allocate memory for page offset */ - fc_trace_entries.page_offset = vmalloc(fc_trace_max_entries * - sizeof(unsigned long)); + fc_trace_entries.page_offset = + vmalloc(array_size(fc_trace_max_entries, + sizeof(unsigned long))); if (!fc_trace_entries.page_offset) { pr_err("fnic:Failed to allocate memory for page_offset\n"); if (fnic_fc_ctlr_trace_buf_p) { diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 3a9eca163db8..15c7f3b6f35e 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1923,8 +1923,8 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, } spin_unlock_irqrestore(&h->reset_lock, flags); - added = kzalloc(sizeof(*added) * HPSA_MAX_DEVICES, GFP_KERNEL); - removed = kzalloc(sizeof(*removed) * HPSA_MAX_DEVICES, GFP_KERNEL); + added = kcalloc(HPSA_MAX_DEVICES, sizeof(*added), GFP_KERNEL); + removed = kcalloc(HPSA_MAX_DEVICES, sizeof(*removed), GFP_KERNEL); if (!added || !removed) { dev_warn(&h->pdev->dev, "out of memory in " @@ -2171,14 +2171,15 @@ static int hpsa_allocate_ioaccel2_sg_chain_blocks(struct ctlr_info *h) return 0; h->ioaccel2_cmd_sg_list = - kzalloc(sizeof(*h->ioaccel2_cmd_sg_list) * h->nr_cmds, + kcalloc(h->nr_cmds, sizeof(*h->ioaccel2_cmd_sg_list), GFP_KERNEL); if (!h->ioaccel2_cmd_sg_list) return -ENOMEM; for (i = 0; i < h->nr_cmds; i++) { h->ioaccel2_cmd_sg_list[i] = - kmalloc(sizeof(*h->ioaccel2_cmd_sg_list[i]) * - h->maxsgentries, GFP_KERNEL); + kmalloc_array(h->maxsgentries, + sizeof(*h->ioaccel2_cmd_sg_list[i]), + GFP_KERNEL); if (!h->ioaccel2_cmd_sg_list[i]) goto clean; } @@ -2210,14 +2211,15 @@ static int hpsa_alloc_sg_chain_blocks(struct ctlr_info *h) if (h->chainsize <= 0) return 0; - h->cmd_sg_list = kzalloc(sizeof(*h->cmd_sg_list) * h->nr_cmds, - GFP_KERNEL); + h->cmd_sg_list = kcalloc(h->nr_cmds, sizeof(*h->cmd_sg_list), + GFP_KERNEL); if (!h->cmd_sg_list) return -ENOMEM; for (i = 0; i < h->nr_cmds; i++) { - h->cmd_sg_list[i] = kmalloc(sizeof(*h->cmd_sg_list[i]) * - h->chainsize, GFP_KERNEL); + h->cmd_sg_list[i] = kmalloc_array(h->chainsize, + sizeof(*h->cmd_sg_list[i]), + GFP_KERNEL); if (!h->cmd_sg_list[i]) goto clean; @@ -4319,7 +4321,7 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h) bool physical_device; DECLARE_BITMAP(lunzerobits, MAX_EXT_TARGETS); - currentsd = kzalloc(sizeof(*currentsd) * HPSA_MAX_DEVICES, GFP_KERNEL); + currentsd = kcalloc(HPSA_MAX_DEVICES, sizeof(*currentsd), GFP_KERNEL); physdev_list = kzalloc(sizeof(*physdev_list), GFP_KERNEL); logdev_list = kzalloc(sizeof(*logdev_list), GFP_KERNEL); tmpdevice = kzalloc(sizeof(*tmpdevice), GFP_KERNEL); @@ -6402,12 +6404,12 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp) status = -EINVAL; goto cleanup1; } - buff = kzalloc(SG_ENTRIES_IN_CMD * sizeof(char *), GFP_KERNEL); + buff = kcalloc(SG_ENTRIES_IN_CMD, sizeof(char *), GFP_KERNEL); if (!buff) { status = -ENOMEM; goto cleanup1; } - buff_size = kmalloc(SG_ENTRIES_IN_CMD * sizeof(int), GFP_KERNEL); + buff_size = kmalloc_array(SG_ENTRIES_IN_CMD, sizeof(int), GFP_KERNEL); if (!buff_size) { status = -ENOMEM; goto cleanup1; @@ -7151,7 +7153,7 @@ static int controller_reset_failed(struct CfgTable __iomem *cfgtable) char *driver_ver, *old_driver_ver; int rc, size = sizeof(cfgtable->driver_version); - old_driver_ver = kmalloc(2 * size, GFP_KERNEL); + old_driver_ver = kmalloc_array(2, size, GFP_KERNEL); if (!old_driver_ver) return -ENOMEM; driver_ver = old_driver_ver + size; @@ -7931,9 +7933,9 @@ static void hpsa_free_cmd_pool(struct ctlr_info *h) static int hpsa_alloc_cmd_pool(struct ctlr_info *h) { - h->cmd_pool_bits = kzalloc( - DIV_ROUND_UP(h->nr_cmds, BITS_PER_LONG) * - sizeof(unsigned long), GFP_KERNEL); + h->cmd_pool_bits = kcalloc(DIV_ROUND_UP(h->nr_cmds, BITS_PER_LONG), + sizeof(unsigned long), + GFP_KERNEL); h->cmd_pool = pci_alloc_consistent(h->pdev, h->nr_cmds * sizeof(*h->cmd_pool), &(h->cmd_pool_dhandle)); @@ -8507,7 +8509,7 @@ static struct ctlr_info *hpda_alloc_ctlr_info(void) if (!h) return NULL; - h->reply_map = kzalloc(sizeof(*h->reply_map) * nr_cpu_ids, GFP_KERNEL); + h->reply_map = kcalloc(nr_cpu_ids, sizeof(*h->reply_map), GFP_KERNEL); if (!h->reply_map) { kfree(h); return NULL; @@ -8869,7 +8871,7 @@ out: kfree(options); } -static void hpsa_shutdown(struct pci_dev *pdev) +static void __hpsa_shutdown(struct pci_dev *pdev) { struct ctlr_info *h; @@ -8884,6 +8886,12 @@ static void hpsa_shutdown(struct pci_dev *pdev) hpsa_disable_interrupt_mode(h); /* pci_init 2 */ } +static void hpsa_shutdown(struct pci_dev *pdev) +{ + __hpsa_shutdown(pdev); + pci_disable_device(pdev); +} + static void hpsa_free_device_info(struct ctlr_info *h) { int i; @@ -8927,7 +8935,7 @@ static void hpsa_remove_one(struct pci_dev *pdev) scsi_remove_host(h->scsi_host); /* init_one 8 */ /* includes hpsa_free_irqs - init_one 4 */ /* includes hpsa_disable_interrupt_mode - pci_init 2 */ - hpsa_shutdown(pdev); + __hpsa_shutdown(pdev); hpsa_free_device_info(h); /* scan */ diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 6615ad8754b8..0a9b8b387bd2 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -4331,9 +4331,11 @@ static int ipr_alloc_dump(struct ipr_ioa_cfg *ioa_cfg) } if (ioa_cfg->sis64) - ioa_data = vmalloc(IPR_FMT3_MAX_NUM_DUMP_PAGES * sizeof(__be32 *)); + ioa_data = vmalloc(array_size(IPR_FMT3_MAX_NUM_DUMP_PAGES, + sizeof(__be32 *))); else - ioa_data = vmalloc(IPR_FMT2_MAX_NUM_DUMP_PAGES * sizeof(__be32 *)); + ioa_data = vmalloc(array_size(IPR_FMT2_MAX_NUM_DUMP_PAGES, + sizeof(__be32 *))); if (!ioa_data) { ipr_err("Dump memory allocation failed\n"); @@ -9713,8 +9715,9 @@ static int ipr_alloc_mem(struct ipr_ioa_cfg *ioa_cfg) int i, rc = -ENOMEM; ENTER; - ioa_cfg->res_entries = kzalloc(sizeof(struct ipr_resource_entry) * - ioa_cfg->max_devs_supported, GFP_KERNEL); + ioa_cfg->res_entries = kcalloc(ioa_cfg->max_devs_supported, + sizeof(struct ipr_resource_entry), + GFP_KERNEL); if (!ioa_cfg->res_entries) goto out; @@ -9775,8 +9778,9 @@ static int ipr_alloc_mem(struct ipr_ioa_cfg *ioa_cfg) list_add_tail(&ioa_cfg->hostrcb[i]->queue, &ioa_cfg->hostrcb_free_q); } - ioa_cfg->trace = kzalloc(sizeof(struct ipr_trace_entry) * - IPR_NUM_TRACE_ENTRIES, GFP_KERNEL); + ioa_cfg->trace = kcalloc(IPR_NUM_TRACE_ENTRIES, + sizeof(struct ipr_trace_entry), + GFP_KERNEL); if (!ioa_cfg->trace) goto out_free_hostrcb_dma; diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c index 05cf4daf8788..08c7b1e25fe4 100644 --- a/drivers/scsi/isci/init.c +++ b/drivers/scsi/isci/init.c @@ -232,14 +232,14 @@ static int isci_register_sas_ha(struct isci_host *isci_host) struct asd_sas_phy **sas_phys; struct asd_sas_port **sas_ports; - sas_phys = devm_kzalloc(&isci_host->pdev->dev, - SCI_MAX_PHYS * sizeof(void *), + sas_phys = devm_kcalloc(&isci_host->pdev->dev, + SCI_MAX_PHYS, sizeof(void *), GFP_KERNEL); if (!sas_phys) return -ENOMEM; - sas_ports = devm_kzalloc(&isci_host->pdev->dev, - SCI_MAX_PORTS * sizeof(void *), + sas_ports = devm_kcalloc(&isci_host->pdev->dev, + SCI_MAX_PORTS, sizeof(void *), GFP_KERNEL); if (!sas_ports) return -ENOMEM; diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 71bdc0b52cf9..d6093838f5f2 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -2576,7 +2576,7 @@ iscsi_pool_init(struct iscsi_pool *q, int max, void ***items, int item_size) * the array. */ if (items) num_arrays++; - q->pool = kvzalloc(num_arrays * max * sizeof(void*), GFP_KERNEL); + q->pool = kvcalloc(num_arrays * max, sizeof(void *), GFP_KERNEL); if (q->pool == NULL) return -ENOMEM; diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 8b7114348def..fadc99cb60df 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -443,7 +443,7 @@ static int sas_expander_discover(struct domain_device *dev) struct expander_device *ex = &dev->ex_dev; int res = -ENOMEM; - ex->ex_phy = kzalloc(sizeof(*ex->ex_phy)*ex->num_phys, GFP_KERNEL); + ex->ex_phy = kcalloc(ex->num_phys, sizeof(*ex->ex_phy), GFP_KERNEL); if (!ex->ex_phy) return -ENOMEM; diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 7ae343b14630..52cae87da0d2 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -5723,8 +5723,9 @@ lpfc_sli_driver_resource_setup(struct lpfc_hba *phba) } if (!phba->sli.sli3_ring) - phba->sli.sli3_ring = kzalloc(LPFC_SLI3_MAX_RING * - sizeof(struct lpfc_sli_ring), GFP_KERNEL); + phba->sli.sli3_ring = kcalloc(LPFC_SLI3_MAX_RING, + sizeof(struct lpfc_sli_ring), + GFP_KERNEL); if (!phba->sli.sli3_ring) return -ENOMEM; @@ -6233,7 +6234,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) /* Allocate eligible FCF bmask memory for FCF roundrobin failover */ longs = (LPFC_SLI4_FCF_TBL_INDX_MAX + BITS_PER_LONG - 1)/BITS_PER_LONG; - phba->fcf.fcf_rr_bmask = kzalloc(longs * sizeof(unsigned long), + phba->fcf.fcf_rr_bmask = kcalloc(longs, sizeof(unsigned long), GFP_KERNEL); if (!phba->fcf.fcf_rr_bmask) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c index 41361662ff08..0758edb9dfe2 100644 --- a/drivers/scsi/lpfc/lpfc_mem.c +++ b/drivers/scsi/lpfc/lpfc_mem.c @@ -120,8 +120,9 @@ lpfc_mem_alloc(struct lpfc_hba *phba, int align) if (!phba->lpfc_mbuf_pool) goto fail_free_dma_buf_pool; - pool->elements = kmalloc(sizeof(struct lpfc_dmabuf) * - LPFC_MBUF_POOL_SIZE, GFP_KERNEL); + pool->elements = kmalloc_array(LPFC_MBUF_POOL_SIZE, + sizeof(struct lpfc_dmabuf), + GFP_KERNEL); if (!pool->elements) goto fail_free_lpfc_mbuf_pool; diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 4b70d53acb72..6f3c00a233ec 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -1720,7 +1720,7 @@ lpfc_sli_next_iotag(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) - LPFC_IOCBQ_LOOKUP_INCREMENT)) { new_len = psli->iocbq_lookup_len + LPFC_IOCBQ_LOOKUP_INCREMENT; spin_unlock_irq(&phba->hbalock); - new_arr = kzalloc(new_len * sizeof (struct lpfc_iocbq *), + new_arr = kcalloc(new_len, sizeof(struct lpfc_iocbq *), GFP_KERNEL); if (new_arr) { spin_lock_irq(&phba->hbalock); @@ -5142,16 +5142,17 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba) */ if ((phba->vpi_bmask == NULL) && (phba->vpi_ids == NULL)) { longs = (phba->max_vpi + BITS_PER_LONG) / BITS_PER_LONG; - phba->vpi_bmask = kzalloc(longs * sizeof(unsigned long), + phba->vpi_bmask = kcalloc(longs, + sizeof(unsigned long), GFP_KERNEL); if (!phba->vpi_bmask) { rc = -ENOMEM; goto lpfc_sli_hba_setup_error; } - phba->vpi_ids = kzalloc( - (phba->max_vpi+1) * sizeof(uint16_t), - GFP_KERNEL); + phba->vpi_ids = kcalloc(phba->max_vpi + 1, + sizeof(uint16_t), + GFP_KERNEL); if (!phba->vpi_ids) { kfree(phba->vpi_bmask); rc = -ENOMEM; @@ -5836,14 +5837,14 @@ lpfc_sli4_alloc_extent(struct lpfc_hba *phba, uint16_t type) length = sizeof(struct lpfc_rsrc_blks); switch (type) { case LPFC_RSC_TYPE_FCOE_RPI: - phba->sli4_hba.rpi_bmask = kzalloc(longs * + phba->sli4_hba.rpi_bmask = kcalloc(longs, sizeof(unsigned long), GFP_KERNEL); if (unlikely(!phba->sli4_hba.rpi_bmask)) { rc = -ENOMEM; goto err_exit; } - phba->sli4_hba.rpi_ids = kzalloc(rsrc_id_cnt * + phba->sli4_hba.rpi_ids = kcalloc(rsrc_id_cnt, sizeof(uint16_t), GFP_KERNEL); if (unlikely(!phba->sli4_hba.rpi_ids)) { @@ -5865,15 +5866,13 @@ lpfc_sli4_alloc_extent(struct lpfc_hba *phba, uint16_t type) ext_blk_list = &phba->sli4_hba.lpfc_rpi_blk_list; break; case LPFC_RSC_TYPE_FCOE_VPI: - phba->vpi_bmask = kzalloc(longs * - sizeof(unsigned long), + phba->vpi_bmask = kcalloc(longs, sizeof(unsigned long), GFP_KERNEL); if (unlikely(!phba->vpi_bmask)) { rc = -ENOMEM; goto err_exit; } - phba->vpi_ids = kzalloc(rsrc_id_cnt * - sizeof(uint16_t), + phba->vpi_ids = kcalloc(rsrc_id_cnt, sizeof(uint16_t), GFP_KERNEL); if (unlikely(!phba->vpi_ids)) { kfree(phba->vpi_bmask); @@ -5887,7 +5886,7 @@ lpfc_sli4_alloc_extent(struct lpfc_hba *phba, uint16_t type) ext_blk_list = &phba->lpfc_vpi_blk_list; break; case LPFC_RSC_TYPE_FCOE_XRI: - phba->sli4_hba.xri_bmask = kzalloc(longs * + phba->sli4_hba.xri_bmask = kcalloc(longs, sizeof(unsigned long), GFP_KERNEL); if (unlikely(!phba->sli4_hba.xri_bmask)) { @@ -5895,7 +5894,7 @@ lpfc_sli4_alloc_extent(struct lpfc_hba *phba, uint16_t type) goto err_exit; } phba->sli4_hba.max_cfg_param.xri_used = 0; - phba->sli4_hba.xri_ids = kzalloc(rsrc_id_cnt * + phba->sli4_hba.xri_ids = kcalloc(rsrc_id_cnt, sizeof(uint16_t), GFP_KERNEL); if (unlikely(!phba->sli4_hba.xri_ids)) { @@ -5910,14 +5909,14 @@ lpfc_sli4_alloc_extent(struct lpfc_hba *phba, uint16_t type) ext_blk_list = &phba->sli4_hba.lpfc_xri_blk_list; break; case LPFC_RSC_TYPE_FCOE_VFI: - phba->sli4_hba.vfi_bmask = kzalloc(longs * + phba->sli4_hba.vfi_bmask = kcalloc(longs, sizeof(unsigned long), GFP_KERNEL); if (unlikely(!phba->sli4_hba.vfi_bmask)) { rc = -ENOMEM; goto err_exit; } - phba->sli4_hba.vfi_ids = kzalloc(rsrc_id_cnt * + phba->sli4_hba.vfi_ids = kcalloc(rsrc_id_cnt, sizeof(uint16_t), GFP_KERNEL); if (unlikely(!phba->sli4_hba.vfi_ids)) { @@ -6250,15 +6249,14 @@ lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba) } base = phba->sli4_hba.max_cfg_param.rpi_base; longs = (count + BITS_PER_LONG - 1) / BITS_PER_LONG; - phba->sli4_hba.rpi_bmask = kzalloc(longs * + phba->sli4_hba.rpi_bmask = kcalloc(longs, sizeof(unsigned long), GFP_KERNEL); if (unlikely(!phba->sli4_hba.rpi_bmask)) { rc = -ENOMEM; goto err_exit; } - phba->sli4_hba.rpi_ids = kzalloc(count * - sizeof(uint16_t), + phba->sli4_hba.rpi_ids = kcalloc(count, sizeof(uint16_t), GFP_KERNEL); if (unlikely(!phba->sli4_hba.rpi_ids)) { rc = -ENOMEM; @@ -6279,15 +6277,13 @@ lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba) } base = phba->sli4_hba.max_cfg_param.vpi_base; longs = (count + BITS_PER_LONG - 1) / BITS_PER_LONG; - phba->vpi_bmask = kzalloc(longs * - sizeof(unsigned long), + phba->vpi_bmask = kcalloc(longs, sizeof(unsigned long), GFP_KERNEL); if (unlikely(!phba->vpi_bmask)) { rc = -ENOMEM; goto free_rpi_ids; } - phba->vpi_ids = kzalloc(count * - sizeof(uint16_t), + phba->vpi_ids = kcalloc(count, sizeof(uint16_t), GFP_KERNEL); if (unlikely(!phba->vpi_ids)) { rc = -ENOMEM; @@ -6308,7 +6304,7 @@ lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba) } base = phba->sli4_hba.max_cfg_param.xri_base; longs = (count + BITS_PER_LONG - 1) / BITS_PER_LONG; - phba->sli4_hba.xri_bmask = kzalloc(longs * + phba->sli4_hba.xri_bmask = kcalloc(longs, sizeof(unsigned long), GFP_KERNEL); if (unlikely(!phba->sli4_hba.xri_bmask)) { @@ -6316,8 +6312,7 @@ lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba) goto free_vpi_ids; } phba->sli4_hba.max_cfg_param.xri_used = 0; - phba->sli4_hba.xri_ids = kzalloc(count * - sizeof(uint16_t), + phba->sli4_hba.xri_ids = kcalloc(count, sizeof(uint16_t), GFP_KERNEL); if (unlikely(!phba->sli4_hba.xri_ids)) { rc = -ENOMEM; @@ -6338,15 +6333,14 @@ lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba) } base = phba->sli4_hba.max_cfg_param.vfi_base; longs = (count + BITS_PER_LONG - 1) / BITS_PER_LONG; - phba->sli4_hba.vfi_bmask = kzalloc(longs * + phba->sli4_hba.vfi_bmask = kcalloc(longs, sizeof(unsigned long), GFP_KERNEL); if (unlikely(!phba->sli4_hba.vfi_bmask)) { rc = -ENOMEM; goto free_xri_ids; } - phba->sli4_hba.vfi_ids = kzalloc(count * - sizeof(uint16_t), + phba->sli4_hba.vfi_ids = kcalloc(count, sizeof(uint16_t), GFP_KERNEL); if (unlikely(!phba->sli4_hba.vfi_ids)) { rc = -ENOMEM; diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index c9d33b1268cb..81bc12dedf41 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c @@ -840,7 +840,7 @@ lpfc_create_vport_work_array(struct lpfc_hba *phba) struct lpfc_vport *port_iterator; struct lpfc_vport **vports; int index = 0; - vports = kzalloc((phba->max_vports + 1) * sizeof(struct lpfc_vport *), + vports = kcalloc(phba->max_vports + 1, sizeof(struct lpfc_vport *), GFP_KERNEL); if (vports == NULL) return NULL; diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c index 8c4d3003b68b..177701dfdfcb 100644 --- a/drivers/scsi/mac53c94.c +++ b/drivers/scsi/mac53c94.c @@ -464,8 +464,9 @@ static int mac53c94_probe(struct macio_dev *mdev, const struct of_device_id *mat * +1 to allow for aligning. * XXX FIXME: Use DMA consistent routines */ - dma_cmd_space = kmalloc((host->sg_tablesize + 2) * - sizeof(struct dbdma_cmd), GFP_KERNEL); + dma_cmd_space = kmalloc_array(host->sg_tablesize + 2, + sizeof(struct dbdma_cmd), + GFP_KERNEL); if (dma_cmd_space == 0) { printk(KERN_ERR "mac53c94: couldn't allocate dma " "command space for %pOF\n", node); diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 3b3767e240d8..8e8cf1145d7f 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -4292,7 +4292,8 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) goto out_host_put; } - adapter->scb_list = kmalloc(sizeof(scb_t) * MAX_COMMANDS, GFP_KERNEL); + adapter->scb_list = kmalloc_array(MAX_COMMANDS, sizeof(scb_t), + GFP_KERNEL); if (!adapter->scb_list) { dev_warn(&pdev->dev, "out of RAM\n"); goto out_free_cmd_buffer; diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c index bb802b0c12b8..8428247015db 100644 --- a/drivers/scsi/megaraid/megaraid_mm.c +++ b/drivers/scsi/megaraid/megaraid_mm.c @@ -935,10 +935,12 @@ mraid_mm_register_adp(mraid_mmadp_t *lld_adp) * Allocate single blocks of memory for all required kiocs, * mailboxes and passthru structures. */ - adapter->kioc_list = kmalloc(sizeof(uioc_t) * lld_adp->max_kioc, - GFP_KERNEL); - adapter->mbox_list = kmalloc(sizeof(mbox64_t) * lld_adp->max_kioc, - GFP_KERNEL); + adapter->kioc_list = kmalloc_array(lld_adp->max_kioc, + sizeof(uioc_t), + GFP_KERNEL); + adapter->mbox_list = kmalloc_array(lld_adp->max_kioc, + sizeof(mbox64_t), + GFP_KERNEL); adapter->pthru_dma_pool = dma_pool_create("megaraid mm pthru pool", &adapter->pdev->dev, sizeof(mraid_passthru_t), diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index c5d0c4bd71d2..71d97573a667 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -5419,9 +5419,9 @@ static int megasas_init_fw(struct megasas_instance *instance) /* stream detection initialization */ if (instance->adapter_type == VENTURA_SERIES) { fusion->stream_detect_by_ld = - kzalloc(sizeof(struct LD_STREAM_DETECT *) - * MAX_LOGICAL_DRIVES_EXT, - GFP_KERNEL); + kcalloc(MAX_LOGICAL_DRIVES_EXT, + sizeof(struct LD_STREAM_DETECT *), + GFP_KERNEL); if (!fusion->stream_detect_by_ld) { dev_err(&instance->pdev->dev, "unable to allocate stream detection for pool of LDs\n"); @@ -6139,7 +6139,7 @@ static inline int megasas_alloc_mfi_ctrl_mem(struct megasas_instance *instance) */ static int megasas_alloc_ctrl_mem(struct megasas_instance *instance) { - instance->reply_map = kzalloc(sizeof(unsigned int) * nr_cpu_ids, + instance->reply_map = kcalloc(nr_cpu_ids, sizeof(unsigned int), GFP_KERNEL); if (!instance->reply_map) return -ENOMEM; diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 98a7a090b75e..94c23ad51179 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -487,7 +487,7 @@ megasas_alloc_cmdlist_fusion(struct megasas_instance *instance) * commands. */ fusion->cmd_list = - kzalloc(sizeof(struct megasas_cmd_fusion *) * max_mpt_cmd, + kcalloc(max_mpt_cmd, sizeof(struct megasas_cmd_fusion *), GFP_KERNEL); if (!fusion->cmd_list) { dev_err(&instance->pdev->dev, @@ -4829,8 +4829,9 @@ megasas_alloc_fusion_context(struct megasas_instance *instance) (PLD_SPAN_INFO)__get_free_pages(GFP_KERNEL | __GFP_ZERO, fusion->log_to_span_pages); if (!fusion->log_to_span) { - fusion->log_to_span = vzalloc(MAX_LOGICAL_DRIVES_EXT * - sizeof(LD_SPAN_INFO)); + fusion->log_to_span = + vzalloc(array_size(MAX_LOGICAL_DRIVES_EXT, + sizeof(LD_SPAN_INFO))); if (!fusion->log_to_span) { dev_err(&instance->pdev->dev, "Failed from %s %d\n", __func__, __LINE__); @@ -4844,8 +4845,9 @@ megasas_alloc_fusion_context(struct megasas_instance *instance) (struct LD_LOAD_BALANCE_INFO *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, fusion->load_balance_info_pages); if (!fusion->load_balance_info) { - fusion->load_balance_info = vzalloc(MAX_LOGICAL_DRIVES_EXT * - sizeof(struct LD_LOAD_BALANCE_INFO)); + fusion->load_balance_info = + vzalloc(array_size(MAX_LOGICAL_DRIVES_EXT, + sizeof(struct LD_LOAD_BALANCE_INFO))); if (!fusion->load_balance_info) dev_err(&instance->pdev->dev, "Failed to allocate load_balance_info, " "continuing without Load Balance support\n"); diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index bf04fa90f433..569392d0d4c9 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -3348,6 +3348,7 @@ _base_mpi_ep_writeq(__u64 b, volatile void __iomem *addr, spin_lock_irqsave(writeq_lock, flags); writel((u32)(data_out), addr); writel((u32)(data_out >> 32), (addr + 4)); + mmiowb(); spin_unlock_irqrestore(writeq_lock, flags); } diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index 2bbe797f8c3d..7a1a1edde35d 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c @@ -381,7 +381,7 @@ static int osst_execute(struct osst_request *SRpnt, const unsigned char *cmd, struct scatterlist *sg, *sgl = (struct scatterlist *)buffer; int i; - pages = kzalloc(use_sg * sizeof(struct page *), GFP_KERNEL); + pages = kcalloc(use_sg, sizeof(struct page *), GFP_KERNEL); if (!pages) goto free_req; @@ -1488,7 +1488,7 @@ static int osst_read_back_buffer_and_rewrite(struct osst_tape * STp, struct osst int dbg = debugging; #endif - if ((buffer = vmalloc((nframes + 1) * OS_DATA_SIZE)) == NULL) + if ((buffer = vmalloc(array_size((nframes + 1), OS_DATA_SIZE))) == NULL) return (-EIO); printk(KERN_INFO "%s:I: Reading back %d frames from drive buffer%s\n", @@ -5856,7 +5856,9 @@ static int osst_probe(struct device *dev) /* if this is the first attach, build the infrastructure */ write_lock(&os_scsi_tapes_lock); if (os_scsi_tapes == NULL) { - os_scsi_tapes = kmalloc(osst_max_dev * sizeof(struct osst_tape *), GFP_ATOMIC); + os_scsi_tapes = kmalloc_array(osst_max_dev, + sizeof(struct osst_tape *), + GFP_ATOMIC); if (os_scsi_tapes == NULL) { write_unlock(&os_scsi_tapes_lock); printk(KERN_ERR "osst :E: Unable to allocate array for OnStream SCSI tapes.\n"); diff --git a/drivers/scsi/pm8001/pm8001_ctl.c b/drivers/scsi/pm8001/pm8001_ctl.c index 596f3ff965f5..d193961ea82f 100644 --- a/drivers/scsi/pm8001/pm8001_ctl.c +++ b/drivers/scsi/pm8001/pm8001_ctl.c @@ -705,7 +705,7 @@ static ssize_t pm8001_store_update_fw(struct device *cdev, return -EINPROGRESS; pm8001_ha->fw_status = FLASH_IN_PROGRESS; - cmd_ptr = kzalloc(count*2, GFP_KERNEL); + cmd_ptr = kcalloc(count, 2, GFP_KERNEL); if (!cmd_ptr) { pm8001_ha->fw_status = FAIL_OUT_MEMORY; return -ENOMEM; diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index 95530393872d..4e86994e10e8 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -4873,8 +4873,9 @@ static int pmcraid_allocate_config_buffers(struct pmcraid_instance *pinstance) int i; pinstance->res_entries = - kzalloc(sizeof(struct pmcraid_resource_entry) * - PMCRAID_MAX_RESOURCES, GFP_KERNEL); + kcalloc(PMCRAID_MAX_RESOURCES, + sizeof(struct pmcraid_resource_entry), + GFP_KERNEL); if (NULL == pinstance->res_entries) { pmcraid_err("failed to allocate memory for resource table\n"); diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c index 32ee7f62fef9..cf274a79e77a 100644 --- a/drivers/scsi/qedi/qedi_main.c +++ b/drivers/scsi/qedi/qedi_main.c @@ -524,7 +524,7 @@ static int qedi_init_id_tbl(struct qedi_portid_tbl *id_tbl, u16 size, id_tbl->max = size; id_tbl->next = next; spin_lock_init(&id_tbl->lock); - id_tbl->table = kzalloc(DIV_ROUND_UP(size, 32) * 4, GFP_KERNEL); + id_tbl->table = kcalloc(DIV_ROUND_UP(size, 32), 4, GFP_KERNEL); if (!id_tbl->table) return -ENOMEM; diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 1aa3720ea2ed..7b675243bd16 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -3089,8 +3089,9 @@ qla2x00_alloc_outstanding_cmds(struct qla_hw_data *ha, struct req_que *req) req->num_outstanding_cmds = ha->cur_fw_iocb_count; } - req->outstanding_cmds = kzalloc(sizeof(srb_t *) * - req->num_outstanding_cmds, GFP_KERNEL); + req->outstanding_cmds = kcalloc(req->num_outstanding_cmds, + sizeof(srb_t *), + GFP_KERNEL); if (!req->outstanding_cmds) { /* @@ -3098,8 +3099,9 @@ qla2x00_alloc_outstanding_cmds(struct qla_hw_data *ha, struct req_que *req) * initialization. */ req->num_outstanding_cmds = MIN_OUTSTANDING_COMMANDS; - req->outstanding_cmds = kzalloc(sizeof(srb_t *) * - req->num_outstanding_cmds, GFP_KERNEL); + req->outstanding_cmds = kcalloc(req->num_outstanding_cmds, + sizeof(srb_t *), + GFP_KERNEL); if (!req->outstanding_cmds) { ql_log(ql_log_fatal, NULL, 0x0126, @@ -5007,7 +5009,8 @@ qla2x00_iidma_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) return; if (fcport->fp_speed == PORT_SPEED_UNKNOWN || - fcport->fp_speed > ha->link_data_rate) + fcport->fp_speed > ha->link_data_rate || + !ha->flags.gpsc_supported) return; rval = qla2x00_set_idma_speed(vha, fcport->loop_id, fcport->fp_speed, diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index a3dc83f9444d..9fa5a2557f2c 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -2494,8 +2494,12 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) ox_id = le16_to_cpu(sts24->ox_id); par_sense_len = sizeof(sts24->data); /* Valid values of the retry delay timer are 0x1-0xffef */ - if (sts24->retry_delay > 0 && sts24->retry_delay < 0xfff1) - retry_delay = sts24->retry_delay; + if (sts24->retry_delay > 0 && sts24->retry_delay < 0xfff1) { + retry_delay = sts24->retry_delay & 0x3fff; + ql_dbg(ql_dbg_io, sp->vha, 0x3033, + "%s: scope=%#x retry_delay=%#x\n", __func__, + sts24->retry_delay >> 14, retry_delay); + } } else { if (scsi_status & SS_SENSE_LEN_VALID) sense_len = le16_to_cpu(sts->req_sense_length); @@ -3434,8 +3438,9 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) "Adjusted Max no of queues pairs: %d.\n", ha->max_qpairs); } } - ha->msix_entries = kzalloc(sizeof(struct qla_msix_entry) * - ha->msix_count, GFP_KERNEL); + ha->msix_entries = kcalloc(ha->msix_count, + sizeof(struct qla_msix_entry), + GFP_KERNEL); if (!ha->msix_entries) { ql_log(ql_log_fatal, vha, 0x00c8, "Failed to allocate memory for ha->msix_entries.\n"); diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index d8a36c13aeda..7e875f575229 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -292,6 +292,14 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) if (time_after(jiffies, wait_time)) break; + /* + * Check if it's UNLOADING, cause we cannot poll in + * this case, or else a NULL pointer dereference + * is triggered. + */ + if (unlikely(test_bit(UNLOADING, &base_vha->dpc_flags))) + return QLA_FUNCTION_TIMEOUT; + /* Check for pending interrupts. */ qla2x00_poll(ha->rsp_q_map[0]); diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index 872d66dd79cd..de2bc78449e7 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -1230,7 +1230,7 @@ qla82xx_pinit_from_rom(scsi_qla_host_t *vha) ql_log(ql_log_info, vha, 0x0072, "%d CRB init values found in ROM.\n", n); - buf = kmalloc(n * sizeof(struct crb_addr_pair), GFP_KERNEL); + buf = kmalloc_array(n, sizeof(struct crb_addr_pair), GFP_KERNEL); if (buf == NULL) { ql_log(ql_log_fatal, vha, 0x010c, "Unable to allocate memory.\n"); diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 817c18a8e84d..e881fce7477a 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -410,7 +410,7 @@ static int qla2x00_alloc_queues(struct qla_hw_data *ha, struct req_que *req, struct rsp_que *rsp) { scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - ha->req_q_map = kzalloc(sizeof(struct req_que *) * ha->max_req_queues, + ha->req_q_map = kcalloc(ha->max_req_queues, sizeof(struct req_que *), GFP_KERNEL); if (!ha->req_q_map) { ql_log(ql_log_fatal, vha, 0x003b, @@ -418,7 +418,7 @@ static int qla2x00_alloc_queues(struct qla_hw_data *ha, struct req_que *req, goto fail_req_map; } - ha->rsp_q_map = kzalloc(sizeof(struct rsp_que *) * ha->max_rsp_queues, + ha->rsp_q_map = kcalloc(ha->max_rsp_queues, sizeof(struct rsp_que *), GFP_KERNEL); if (!ha->rsp_q_map) { ql_log(ql_log_fatal, vha, 0x003c, @@ -4045,8 +4045,9 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len, (*rsp)->ring); /* Allocate memory for NVRAM data for vports */ if (ha->nvram_npiv_size) { - ha->npiv_info = kzalloc(sizeof(struct qla_npiv_entry) * - ha->nvram_npiv_size, GFP_KERNEL); + ha->npiv_info = kcalloc(ha->nvram_npiv_size, + sizeof(struct qla_npiv_entry), + GFP_KERNEL); if (!ha->npiv_info) { ql_log_pci(ql_log_fatal, ha->pdev, 0x002d, "Failed to allocate memory for npiv_info.\n"); @@ -4080,8 +4081,9 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len, INIT_LIST_HEAD(&ha->vp_list); /* Allocate memory for our loop_id bitmap */ - ha->loop_id_map = kzalloc(BITS_TO_LONGS(LOOPID_MAP_SIZE) * sizeof(long), - GFP_KERNEL); + ha->loop_id_map = kcalloc(BITS_TO_LONGS(LOOPID_MAP_SIZE), + sizeof(long), + GFP_KERNEL); if (!ha->loop_id_map) goto fail_loop_id_map; else { diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index b85c833099ff..0fea2e2326be 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -6248,8 +6248,9 @@ int qlt_add_target(struct qla_hw_data *ha, struct scsi_qla_host *base_vha) return -ENOMEM; } - tgt->qphints = kzalloc((ha->max_qpairs + 1) * - sizeof(struct qla_qpair_hint), GFP_KERNEL); + tgt->qphints = kcalloc(ha->max_qpairs + 1, + sizeof(struct qla_qpair_hint), + GFP_KERNEL); if (!tgt->qphints) { kfree(tgt); ql_log(ql_log_warn, base_vha, 0x0197, @@ -7089,8 +7090,9 @@ qlt_mem_alloc(struct qla_hw_data *ha) if (!QLA_TGT_MODE_ENABLED()) return 0; - ha->tgt.tgt_vp_map = kzalloc(sizeof(struct qla_tgt_vp_map) * - MAX_MULTI_ID_FABRIC, GFP_KERNEL); + ha->tgt.tgt_vp_map = kcalloc(MAX_MULTI_ID_FABRIC, + sizeof(struct qla_tgt_vp_map), + GFP_KERNEL); if (!ha->tgt.tgt_vp_map) return -ENOMEM; diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 0c2e82af9c0a..7732e9336d43 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -1661,7 +1661,9 @@ static int tcm_qla2xxx_init_lport(struct tcm_qla2xxx_lport *lport) return rc; } - lport->lport_loopid_map = vzalloc(sizeof(struct tcm_qla2xxx_fc_loopid) * 65536); + lport->lport_loopid_map = + vzalloc(array_size(65536, + sizeof(struct tcm_qla2xxx_fc_loopid))); if (!lport->lport_loopid_map) { pr_err("Unable to allocate lport->lport_loopid_map of %zu bytes\n", sizeof(struct tcm_qla2xxx_fc_loopid) * 65536); diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c index 43f73583ef5c..d2b333d629be 100644 --- a/drivers/scsi/qla4xxx/ql4_nx.c +++ b/drivers/scsi/qla4xxx/ql4_nx.c @@ -1077,7 +1077,7 @@ qla4_82xx_pinit_from_rom(struct scsi_qla_host *ha, int verbose) ql4_printk(KERN_INFO, ha, "%s: %d CRB init values found in ROM.\n", DRIVER_NAME, n); - buf = kmalloc(n * sizeof(struct crb_addr_pair), GFP_KERNEL); + buf = kmalloc_array(n, sizeof(struct crb_addr_pair), GFP_KERNEL); if (buf == NULL) { ql4_printk(KERN_WARNING, ha, "%s: [ERROR] Unable to malloc memory.\n", DRIVER_NAME); diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 656c98e116a9..24d7496cd9e2 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -3450,7 +3450,7 @@ static int resp_comp_write(struct scsi_cmnd *scp, return check_condition_result; } dnum = 2 * num; - arr = kzalloc(dnum * lb_size, GFP_ATOMIC); + arr = kcalloc(lb_size, dnum, GFP_ATOMIC); if (NULL == arr) { mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, INSUFF_RES_ASCQ); @@ -5439,7 +5439,8 @@ static int __init scsi_debug_init(void) } map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1; - map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long)); + map_storep = vmalloc(array_size(sizeof(long), + BITS_TO_LONGS(map_size))); pr_info("%lu provisioning blocks\n", map_size); diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c index 323e3dc4bc59..a14fef11776e 100644 --- a/drivers/scsi/sd_zbc.c +++ b/drivers/scsi/sd_zbc.c @@ -442,7 +442,7 @@ static s64 sd_zbc_check_zone_size(struct scsi_disk *sdkp) } else if (this_zone_blocks != zone_blocks && (block + this_zone_blocks < sdkp->capacity || this_zone_blocks > zone_blocks)) { - this_zone_blocks = 0; + zone_blocks = 0; goto out; } block += this_zone_blocks; @@ -494,7 +494,7 @@ out_free: static inline unsigned long * sd_zbc_alloc_zone_bitmap(u32 nr_zones, int numa_node) { - return kzalloc_node(BITS_TO_LONGS(nr_zones) * sizeof(unsigned long), + return kcalloc_node(BITS_TO_LONGS(nr_zones), sizeof(unsigned long), GFP_KERNEL, numa_node); } diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index 62f04c0511cf..0fc39224ce1e 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c @@ -747,7 +747,7 @@ static int ses_intf_add(struct device *cdev, buf = NULL; } page2_not_supported: - scomp = kzalloc(sizeof(struct ses_component) * components, GFP_KERNEL); + scomp = kcalloc(components, sizeof(struct ses_component), GFP_KERNEL); if (!scomp) goto err_free; diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 573763908562..53ae52dbff84 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1045,7 +1045,7 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) else { sg_req_info_t *rinfo; - rinfo = kzalloc(SZ_SG_REQ_INFO * SG_MAX_QUEUE, + rinfo = kcalloc(SG_MAX_QUEUE, SZ_SG_REQ_INFO, GFP_KERNEL); if (!rinfo) return -ENOMEM; diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index 592b6dbf8b35..b78d20b74ed8 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -1820,8 +1820,9 @@ static int pqi_update_scsi_devices(struct pqi_ctrl_info *ctrl_info) num_new_devices = num_physicals + num_logicals; - new_device_list = kmalloc(sizeof(*new_device_list) * - num_new_devices, GFP_KERNEL); + new_device_list = kmalloc_array(num_new_devices, + sizeof(*new_device_list), + GFP_KERNEL); if (!new_device_list) { dev_warn(&ctrl_info->pci_dev->dev, "%s\n", out_of_memory_msg); rc = -ENOMEM; @@ -4251,8 +4252,9 @@ static int pqi_alloc_io_resources(struct pqi_ctrl_info *ctrl_info) struct device *dev; struct pqi_io_request *io_request; - ctrl_info->io_request_pool = kzalloc(ctrl_info->max_io_slots * - sizeof(ctrl_info->io_request_pool[0]), GFP_KERNEL); + ctrl_info->io_request_pool = + kcalloc(ctrl_info->max_io_slots, + sizeof(ctrl_info->io_request_pool[0]), GFP_KERNEL); if (!ctrl_info->io_request_pool) { dev_err(&ctrl_info->pci_dev->dev, diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index c9e27e752c25..50c66ccc4b41 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -3888,7 +3888,7 @@ static struct st_buffer *new_tape_buffer(int need_dma, int max_sg) tb->dma = need_dma; tb->buffer_size = 0; - tb->reserved_pages = kzalloc(max_sg * sizeof(struct page *), + tb->reserved_pages = kcalloc(max_sg, sizeof(struct page *), GFP_KERNEL); if (!tb->reserved_pages) { kfree(tb); @@ -4915,7 +4915,8 @@ static int sgl_map_user_pages(struct st_buffer *STbp, if (count == 0) return 0; - if ((pages = kmalloc(max_pages * sizeof(*pages), GFP_KERNEL)) == NULL) + pages = kmalloc_array(max_pages, sizeof(*pages), GFP_KERNEL); + if (pages == NULL) return -ENOMEM; /* Try to fault in all of the necessary pages */ diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c index e82bde077296..895a9b5ac989 100644 --- a/drivers/scsi/ufs/ufshcd-pltfrm.c +++ b/drivers/scsi/ufs/ufshcd-pltfrm.c @@ -86,8 +86,8 @@ static int ufshcd_parse_clock_info(struct ufs_hba *hba) goto out; } - clkfreq = devm_kzalloc(dev, sz * sizeof(*clkfreq), - GFP_KERNEL); + clkfreq = devm_kcalloc(dev, sz, sizeof(*clkfreq), + GFP_KERNEL); if (!clkfreq) { ret = -ENOMEM; goto out; diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 3a811c5f70ba..397081d320b1 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -3357,8 +3357,8 @@ static int ufshcd_memory_alloc(struct ufs_hba *hba) } /* Allocate memory for local reference block */ - hba->lrb = devm_kzalloc(hba->dev, - hba->nutrs * sizeof(struct ufshcd_lrb), + hba->lrb = devm_kcalloc(hba->dev, + hba->nutrs, sizeof(struct ufshcd_lrb), GFP_KERNEL); if (!hba->lrb) { dev_err(hba->dev, "LRB Memory allocation failed\n"); diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index 45d04631888a..6dc8891ccb74 100644 --- a/drivers/scsi/virtio_scsi.c +++ b/drivers/scsi/virtio_scsi.c @@ -794,9 +794,10 @@ static int virtscsi_init(struct virtio_device *vdev, struct irq_affinity desc = { .pre_vectors = 2 }; num_vqs = vscsi->num_queues + VIRTIO_SCSI_VQ_BASE; - vqs = kmalloc(num_vqs * sizeof(struct virtqueue *), GFP_KERNEL); - callbacks = kmalloc(num_vqs * sizeof(vq_callback_t *), GFP_KERNEL); - names = kmalloc(num_vqs * sizeof(char *), GFP_KERNEL); + vqs = kmalloc_array(num_vqs, sizeof(struct virtqueue *), GFP_KERNEL); + callbacks = kmalloc_array(num_vqs, sizeof(vq_callback_t *), + GFP_KERNEL); + names = kmalloc_array(num_vqs, sizeof(char *), GFP_KERNEL); if (!callbacks || !vqs || !names) { err = -ENOMEM; diff --git a/drivers/sh/clk/cpg.c b/drivers/sh/clk/cpg.c index 7442bc130055..eeb028b9cdb3 100644 --- a/drivers/sh/clk/cpg.c +++ b/drivers/sh/clk/cpg.c @@ -249,7 +249,7 @@ static int __init sh_clk_div_register_ops(struct clk *clks, int nr, int k; freq_table_size *= (nr_divs + 1); - freq_table = kzalloc(freq_table_size * nr, GFP_KERNEL); + freq_table = kcalloc(nr, freq_table_size, GFP_KERNEL); if (!freq_table) { pr_err("%s: unable to alloc memory\n", __func__); return -ENOMEM; diff --git a/drivers/sh/intc/core.c b/drivers/sh/intc/core.c index 8e72bcbd3d6d..46f0f322d4d8 100644 --- a/drivers/sh/intc/core.c +++ b/drivers/sh/intc/core.c @@ -203,7 +203,7 @@ int __init register_intc_controller(struct intc_desc *desc) if (desc->num_resources) { d->nr_windows = desc->num_resources; - d->window = kzalloc(d->nr_windows * sizeof(*d->window), + d->window = kcalloc(d->nr_windows, sizeof(*d->window), GFP_NOWAIT); if (!d->window) goto err1; @@ -230,12 +230,12 @@ int __init register_intc_controller(struct intc_desc *desc) d->nr_reg += hw->ack_regs ? hw->nr_ack_regs : 0; d->nr_reg += hw->subgroups ? hw->nr_subgroups : 0; - d->reg = kzalloc(d->nr_reg * sizeof(*d->reg), GFP_NOWAIT); + d->reg = kcalloc(d->nr_reg, sizeof(*d->reg), GFP_NOWAIT); if (!d->reg) goto err2; #ifdef CONFIG_SMP - d->smp = kzalloc(d->nr_reg * sizeof(*d->smp), GFP_NOWAIT); + d->smp = kcalloc(d->nr_reg, sizeof(*d->smp), GFP_NOWAIT); if (!d->smp) goto err3; #endif @@ -253,7 +253,7 @@ int __init register_intc_controller(struct intc_desc *desc) } if (hw->prio_regs) { - d->prio = kzalloc(hw->nr_vectors * sizeof(*d->prio), + d->prio = kcalloc(hw->nr_vectors, sizeof(*d->prio), GFP_NOWAIT); if (!d->prio) goto err4; @@ -269,7 +269,7 @@ int __init register_intc_controller(struct intc_desc *desc) } if (hw->sense_regs) { - d->sense = kzalloc(hw->nr_vectors * sizeof(*d->sense), + d->sense = kcalloc(hw->nr_vectors, sizeof(*d->sense), GFP_NOWAIT); if (!d->sense) goto err5; diff --git a/drivers/sh/maple/maple.c b/drivers/sh/maple/maple.c index 7525039d812c..2e45988d1259 100644 --- a/drivers/sh/maple/maple.c +++ b/drivers/sh/maple/maple.c @@ -161,7 +161,7 @@ int maple_add_packet(struct maple_device *mdev, u32 function, u32 command, void *sendbuf = NULL; if (length) { - sendbuf = kzalloc(length * 4, GFP_KERNEL); + sendbuf = kcalloc(length, 4, GFP_KERNEL); if (!sendbuf) { ret = -ENOMEM; goto out; diff --git a/drivers/slimbus/qcom-ctrl.c b/drivers/slimbus/qcom-ctrl.c index bb36a8fbc9b1..db1f5135846a 100644 --- a/drivers/slimbus/qcom-ctrl.c +++ b/drivers/slimbus/qcom-ctrl.c @@ -540,7 +540,7 @@ static int qcom_slim_probe(struct platform_device *pdev) ctrl->tx.sl_sz = SLIM_MSGQ_BUF_LEN; ctrl->rx.n = QCOM_RX_MSGS; ctrl->rx.sl_sz = SLIM_MSGQ_BUF_LEN; - ctrl->wr_comp = kzalloc(sizeof(struct completion *) * QCOM_TX_MSGS, + ctrl->wr_comp = kcalloc(QCOM_TX_MSGS, sizeof(struct completion *), GFP_KERNEL); if (!ctrl->wr_comp) return -ENOMEM; diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile index 40523577bdaa..113e884697fd 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile @@ -14,7 +14,7 @@ obj-$(CONFIG_ARCH_MXC) += imx/ obj-$(CONFIG_SOC_XWAY) += lantiq/ obj-y += mediatek/ obj-$(CONFIG_ARCH_MESON) += amlogic/ -obj-$(CONFIG_ARCH_QCOM) += qcom/ +obj-y += qcom/ obj-y += renesas/ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ obj-$(CONFIG_SOC_SAMSUNG) += samsung/ diff --git a/drivers/soc/bcm/raspberrypi-power.c b/drivers/soc/bcm/raspberrypi-power.c index f7ed1187518b..a78dfe0a2b50 100644 --- a/drivers/soc/bcm/raspberrypi-power.c +++ b/drivers/soc/bcm/raspberrypi-power.c @@ -165,8 +165,10 @@ static int rpi_power_probe(struct platform_device *pdev) return -ENOMEM; rpi_domains->xlate.domains = - devm_kzalloc(dev, sizeof(*rpi_domains->xlate.domains) * - RPI_POWER_DOMAIN_COUNT, GFP_KERNEL); + devm_kcalloc(dev, + RPI_POWER_DOMAIN_COUNT, + sizeof(*rpi_domains->xlate.domains), + GFP_KERNEL); if (!rpi_domains->xlate.domains) return -ENOMEM; diff --git a/drivers/soc/fsl/qbman/qman.c b/drivers/soc/fsl/qbman/qman.c index ba3cfa8e279b..ecb22749df0b 100644 --- a/drivers/soc/fsl/qbman/qman.c +++ b/drivers/soc/fsl/qbman/qman.c @@ -1021,7 +1021,8 @@ int qman_alloc_fq_table(u32 _num_fqids) { num_fqids = _num_fqids; - fq_table = vzalloc(num_fqids * 2 * sizeof(struct qman_fq *)); + fq_table = vzalloc(array3_size(sizeof(struct qman_fq *), + num_fqids, 2)); if (!fq_table) return -ENOMEM; @@ -1181,7 +1182,7 @@ static int qman_create_portal(struct qman_portal *portal, qm_dqrr_set_ithresh(p, QMAN_PIRQ_DQRR_ITHRESH); qm_mr_set_ithresh(p, QMAN_PIRQ_MR_ITHRESH); qm_out(p, QM_REG_ITPR, QMAN_PIRQ_IPERIOD); - portal->cgrs = kmalloc(2 * sizeof(*cgrs), GFP_KERNEL); + portal->cgrs = kmalloc_array(2, sizeof(*cgrs), GFP_KERNEL); if (!portal->cgrs) goto fail_cgrs; /* initial snapshot is no-depletion */ diff --git a/drivers/soc/imx/gpc.c b/drivers/soc/imx/gpc.c index c4d35f32af8d..32f0748fd067 100644 --- a/drivers/soc/imx/gpc.c +++ b/drivers/soc/imx/gpc.c @@ -443,17 +443,25 @@ static int imx_gpc_probe(struct platform_device *pdev) if (domain_index >= of_id_data->num_domains) continue; - domain = &imx_gpc_domains[domain_index]; - domain->regmap = regmap; - domain->ipg_rate_mhz = ipg_rate_mhz; - pd_pdev = platform_device_alloc("imx-pgc-power-domain", domain_index); if (!pd_pdev) { of_node_put(np); return -ENOMEM; } - pd_pdev->dev.platform_data = domain; + + ret = platform_device_add_data(pd_pdev, + &imx_gpc_domains[domain_index], + sizeof(imx_gpc_domains[domain_index])); + if (ret) { + platform_device_put(pd_pdev); + of_node_put(np); + return ret; + } + domain = pd_pdev->dev.platform_data; + domain->regmap = regmap; + domain->ipg_rate_mhz = ipg_rate_mhz; + pd_pdev->dev.parent = &pdev->dev; pd_pdev->dev.of_node = np; diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c index afc7ecc3c187..f4e3bd40c72e 100644 --- a/drivers/soc/imx/gpcv2.c +++ b/drivers/soc/imx/gpcv2.c @@ -155,7 +155,7 @@ static int imx7_gpc_pu_pgc_sw_pdn_req(struct generic_pm_domain *genpd) return imx7_gpc_pu_pgc_sw_pxx_req(genpd, false); } -static struct imx7_pgc_domain imx7_pgc_domains[] = { +static const struct imx7_pgc_domain imx7_pgc_domains[] = { [IMX7_POWER_DOMAIN_MIPI_PHY] = { .genpd = { .name = "mipi-phy", @@ -321,11 +321,6 @@ static int imx_gpcv2_probe(struct platform_device *pdev) continue; } - domain = &imx7_pgc_domains[domain_index]; - domain->regmap = regmap; - domain->genpd.power_on = imx7_gpc_pu_pgc_sw_pup_req; - domain->genpd.power_off = imx7_gpc_pu_pgc_sw_pdn_req; - pd_pdev = platform_device_alloc("imx7-pgc-domain", domain_index); if (!pd_pdev) { @@ -334,7 +329,20 @@ static int imx_gpcv2_probe(struct platform_device *pdev) return -ENOMEM; } - pd_pdev->dev.platform_data = domain; + ret = platform_device_add_data(pd_pdev, + &imx7_pgc_domains[domain_index], + sizeof(imx7_pgc_domains[domain_index])); + if (ret) { + platform_device_put(pd_pdev); + of_node_put(np); + return ret; + } + + domain = pd_pdev->dev.platform_data; + domain->regmap = regmap; + domain->genpd.power_on = imx7_gpc_pu_pgc_sw_pup_req; + domain->genpd.power_off = imx7_gpc_pu_pgc_sw_pdn_req; + pd_pdev->dev.parent = dev; pd_pdev->dev.of_node = np; diff --git a/drivers/soc/mediatek/mtk-infracfg.c b/drivers/soc/mediatek/mtk-infracfg.c index 8c310de01e93..958861c9e6ee 100644 --- a/drivers/soc/mediatek/mtk-infracfg.c +++ b/drivers/soc/mediatek/mtk-infracfg.c @@ -17,6 +17,9 @@ #include <linux/soc/mediatek/infracfg.h> #include <asm/processor.h> +#define MTK_POLL_DELAY_US 10 +#define MTK_POLL_TIMEOUT (jiffies_to_usecs(HZ)) + #define INFRA_TOPAXI_PROTECTEN 0x0220 #define INFRA_TOPAXI_PROTECTSTA1 0x0228 #define INFRA_TOPAXI_PROTECTEN_SET 0x0260 @@ -37,7 +40,6 @@ int mtk_infracfg_set_bus_protection(struct regmap *infracfg, u32 mask, bool reg_update) { - unsigned long expired; u32 val; int ret; @@ -47,22 +49,11 @@ int mtk_infracfg_set_bus_protection(struct regmap *infracfg, u32 mask, else regmap_write(infracfg, INFRA_TOPAXI_PROTECTEN_SET, mask); - expired = jiffies + HZ; - - while (1) { - ret = regmap_read(infracfg, INFRA_TOPAXI_PROTECTSTA1, &val); - if (ret) - return ret; - - if ((val & mask) == mask) - break; + ret = regmap_read_poll_timeout(infracfg, INFRA_TOPAXI_PROTECTSTA1, + val, (val & mask) == mask, + MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); - cpu_relax(); - if (time_after(jiffies, expired)) - return -EIO; - } - - return 0; + return ret; } /** @@ -80,30 +71,17 @@ int mtk_infracfg_set_bus_protection(struct regmap *infracfg, u32 mask, int mtk_infracfg_clear_bus_protection(struct regmap *infracfg, u32 mask, bool reg_update) { - unsigned long expired; int ret; + u32 val; if (reg_update) regmap_update_bits(infracfg, INFRA_TOPAXI_PROTECTEN, mask, 0); else regmap_write(infracfg, INFRA_TOPAXI_PROTECTEN_CLR, mask); - expired = jiffies + HZ; - - while (1) { - u32 val; - - ret = regmap_read(infracfg, INFRA_TOPAXI_PROTECTSTA1, &val); - if (ret) - return ret; - - if (!(val & mask)) - break; - - cpu_relax(); - if (time_after(jiffies, expired)) - return -EIO; - } + ret = regmap_read_poll_timeout(infracfg, INFRA_TOPAXI_PROTECTSTA1, + val, !(val & mask), + MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); - return 0; + return ret; } diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c index e9e054a15b7d..2afae64061d8 100644 --- a/drivers/soc/mediatek/mtk-pmic-wrap.c +++ b/drivers/soc/mediatek/mtk-pmic-wrap.c @@ -1458,19 +1458,12 @@ static int pwrap_probe(struct platform_device *pdev) int ret, irq; struct pmic_wrapper *wrp; struct device_node *np = pdev->dev.of_node; - const struct of_device_id *of_id = - of_match_device(of_pwrap_match_tbl, &pdev->dev); const struct of_device_id *of_slave_id = NULL; struct resource *res; - if (!of_id) { - dev_err(&pdev->dev, "Error: No device match found\n"); - return -ENODEV; - } + if (np->child) + of_slave_id = of_match_node(of_slave_match_tbl, np->child); - if (pdev->dev.of_node->child) - of_slave_id = of_match_node(of_slave_match_tbl, - pdev->dev.of_node->child); if (!of_slave_id) { dev_dbg(&pdev->dev, "slave pmic should be defined in dts\n"); return -EINVAL; @@ -1482,7 +1475,7 @@ static int pwrap_probe(struct platform_device *pdev) platform_set_drvdata(pdev, wrp); - wrp->master = of_id->data; + wrp->master = of_device_get_match_data(&pdev->dev); wrp->slave = of_slave_id->data; wrp->dev = &pdev->dev; diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c index d762a46d434f..5b24bb4bfbf6 100644 --- a/drivers/soc/mediatek/mtk-scpsys.c +++ b/drivers/soc/mediatek/mtk-scpsys.c @@ -13,6 +13,7 @@ #include <linux/clk.h> #include <linux/init.h> #include <linux/io.h> +#include <linux/iopoll.h> #include <linux/mfd/syscon.h> #include <linux/of_device.h> #include <linux/platform_device.h> @@ -27,6 +28,13 @@ #include <dt-bindings/power/mt7623a-power.h> #include <dt-bindings/power/mt8173-power.h> +#define MTK_POLL_DELAY_US 10 +#define MTK_POLL_TIMEOUT (jiffies_to_usecs(HZ)) + +#define MTK_SCPD_ACTIVE_WAKEUP BIT(0) +#define MTK_SCPD_FWAIT_SRAM BIT(1) +#define MTK_SCPD_CAPS(_scpd, _x) ((_scpd)->data->caps & (_x)) + #define SPM_VDE_PWR_CON 0x0210 #define SPM_MFG_PWR_CON 0x0214 #define SPM_VEN_PWR_CON 0x0230 @@ -116,7 +124,7 @@ struct scp_domain_data { u32 sram_pdn_ack_bits; u32 bus_prot_mask; enum clk_id clk_id[MAX_CLKS]; - bool active_wakeup; + u8 caps; }; struct scp; @@ -184,12 +192,10 @@ static int scpsys_power_on(struct generic_pm_domain *genpd) { struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd); struct scp *scp = scpd->scp; - unsigned long timeout; - bool expired; void __iomem *ctl_addr = scp->base + scpd->data->ctl_offs; - u32 sram_pdn_ack = scpd->data->sram_pdn_ack_bits; + u32 pdn_ack = scpd->data->sram_pdn_ack_bits; u32 val; - int ret; + int ret, tmp; int i; if (scpd->supply) { @@ -215,23 +221,10 @@ static int scpsys_power_on(struct generic_pm_domain *genpd) writel(val, ctl_addr); /* wait until PWR_ACK = 1 */ - timeout = jiffies + HZ; - expired = false; - while (1) { - ret = scpsys_domain_is_on(scpd); - if (ret > 0) - break; - - if (expired) { - ret = -ETIMEDOUT; - goto err_pwr_ack; - } - - cpu_relax(); - - if (time_after(jiffies, timeout)) - expired = true; - } + ret = readx_poll_timeout(scpsys_domain_is_on, scpd, tmp, tmp > 0, + MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); + if (ret < 0) + goto err_pwr_ack; val &= ~PWR_CLK_DIS_BIT; writel(val, ctl_addr); @@ -245,20 +238,20 @@ static int scpsys_power_on(struct generic_pm_domain *genpd) val &= ~scpd->data->sram_pdn_bits; writel(val, ctl_addr); - /* wait until SRAM_PDN_ACK all 0 */ - timeout = jiffies + HZ; - expired = false; - while (sram_pdn_ack && (readl(ctl_addr) & sram_pdn_ack)) { + /* Either wait until SRAM_PDN_ACK all 0 or have a force wait */ + if (MTK_SCPD_CAPS(scpd, MTK_SCPD_FWAIT_SRAM)) { + /* + * Currently, MTK_SCPD_FWAIT_SRAM is necessary only for + * MT7622_POWER_DOMAIN_WB and thus just a trivial setup is + * applied here. + */ + usleep_range(12000, 12100); - if (expired) { - ret = -ETIMEDOUT; + } else { + ret = readl_poll_timeout(ctl_addr, tmp, (tmp & pdn_ack) == 0, + MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); + if (ret < 0) goto err_pwr_ack; - } - - cpu_relax(); - - if (time_after(jiffies, timeout)) - expired = true; } if (scpd->data->bus_prot_mask) { @@ -289,12 +282,10 @@ static int scpsys_power_off(struct generic_pm_domain *genpd) { struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd); struct scp *scp = scpd->scp; - unsigned long timeout; - bool expired; void __iomem *ctl_addr = scp->base + scpd->data->ctl_offs; u32 pdn_ack = scpd->data->sram_pdn_ack_bits; u32 val; - int ret; + int ret, tmp; int i; if (scpd->data->bus_prot_mask) { @@ -310,19 +301,10 @@ static int scpsys_power_off(struct generic_pm_domain *genpd) writel(val, ctl_addr); /* wait until SRAM_PDN_ACK all 1 */ - timeout = jiffies + HZ; - expired = false; - while (pdn_ack && (readl(ctl_addr) & pdn_ack) != pdn_ack) { - if (expired) { - ret = -ETIMEDOUT; - goto out; - } - - cpu_relax(); - - if (time_after(jiffies, timeout)) - expired = true; - } + ret = readl_poll_timeout(ctl_addr, tmp, (tmp & pdn_ack) == pdn_ack, + MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); + if (ret < 0) + goto out; val |= PWR_ISO_BIT; writel(val, ctl_addr); @@ -340,23 +322,10 @@ static int scpsys_power_off(struct generic_pm_domain *genpd) writel(val, ctl_addr); /* wait until PWR_ACK = 0 */ - timeout = jiffies + HZ; - expired = false; - while (1) { - ret = scpsys_domain_is_on(scpd); - if (ret == 0) - break; - - if (expired) { - ret = -ETIMEDOUT; - goto out; - } - - cpu_relax(); - - if (time_after(jiffies, timeout)) - expired = true; - } + ret = readx_poll_timeout(scpsys_domain_is_on, scpd, tmp, tmp == 0, + MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); + if (ret < 0) + goto out; for (i = 0; i < MAX_CLKS && scpd->clk[i]; i++) clk_disable_unprepare(scpd->clk[i]); @@ -407,15 +376,15 @@ static struct scp *init_scp(struct platform_device *pdev, if (IS_ERR(scp->base)) return ERR_CAST(scp->base); - scp->domains = devm_kzalloc(&pdev->dev, - sizeof(*scp->domains) * num, GFP_KERNEL); + scp->domains = devm_kcalloc(&pdev->dev, + num, sizeof(*scp->domains), GFP_KERNEL); if (!scp->domains) return ERR_PTR(-ENOMEM); pd_data = &scp->pd_data; - pd_data->domains = devm_kzalloc(&pdev->dev, - sizeof(*pd_data->domains) * num, GFP_KERNEL); + pd_data->domains = devm_kcalloc(&pdev->dev, + num, sizeof(*pd_data->domains), GFP_KERNEL); if (!pd_data->domains) return ERR_PTR(-ENOMEM); @@ -469,7 +438,7 @@ static struct scp *init_scp(struct platform_device *pdev, genpd->name = data->name; genpd->power_off = scpsys_power_off; genpd->power_on = scpsys_power_on; - if (scpd->data->active_wakeup) + if (MTK_SCPD_CAPS(scpd, MTK_SCPD_ACTIVE_WAKEUP)) genpd->flags |= GENPD_FLAG_ACTIVE_WAKEUP; } @@ -522,7 +491,7 @@ static const struct scp_domain_data scp_domain_data_mt2701[] = { .bus_prot_mask = MT2701_TOP_AXI_PROT_EN_CONN_M | MT2701_TOP_AXI_PROT_EN_CONN_S, .clk_id = {CLK_NONE}, - .active_wakeup = true, + .caps = MTK_SCPD_ACTIVE_WAKEUP, }, [MT2701_POWER_DOMAIN_DISP] = { .name = "disp", @@ -531,7 +500,7 @@ static const struct scp_domain_data scp_domain_data_mt2701[] = { .sram_pdn_bits = GENMASK(11, 8), .clk_id = {CLK_MM}, .bus_prot_mask = MT2701_TOP_AXI_PROT_EN_MM_M0, - .active_wakeup = true, + .caps = MTK_SCPD_ACTIVE_WAKEUP, }, [MT2701_POWER_DOMAIN_MFG] = { .name = "mfg", @@ -540,7 +509,7 @@ static const struct scp_domain_data scp_domain_data_mt2701[] = { .sram_pdn_bits = GENMASK(11, 8), .sram_pdn_ack_bits = GENMASK(12, 12), .clk_id = {CLK_MFG}, - .active_wakeup = true, + .caps = MTK_SCPD_ACTIVE_WAKEUP, }, [MT2701_POWER_DOMAIN_VDEC] = { .name = "vdec", @@ -549,7 +518,7 @@ static const struct scp_domain_data scp_domain_data_mt2701[] = { .sram_pdn_bits = GENMASK(11, 8), .sram_pdn_ack_bits = GENMASK(12, 12), .clk_id = {CLK_MM}, - .active_wakeup = true, + .caps = MTK_SCPD_ACTIVE_WAKEUP, }, [MT2701_POWER_DOMAIN_ISP] = { .name = "isp", @@ -558,7 +527,7 @@ static const struct scp_domain_data scp_domain_data_mt2701[] = { .sram_pdn_bits = GENMASK(11, 8), .sram_pdn_ack_bits = GENMASK(13, 12), .clk_id = {CLK_MM}, - .active_wakeup = true, + .caps = MTK_SCPD_ACTIVE_WAKEUP, }, [MT2701_POWER_DOMAIN_BDP] = { .name = "bdp", @@ -566,7 +535,7 @@ static const struct scp_domain_data scp_domain_data_mt2701[] = { .ctl_offs = SPM_BDP_PWR_CON, .sram_pdn_bits = GENMASK(11, 8), .clk_id = {CLK_NONE}, - .active_wakeup = true, + .caps = MTK_SCPD_ACTIVE_WAKEUP, }, [MT2701_POWER_DOMAIN_ETH] = { .name = "eth", @@ -575,7 +544,7 @@ static const struct scp_domain_data scp_domain_data_mt2701[] = { .sram_pdn_bits = GENMASK(11, 8), .sram_pdn_ack_bits = GENMASK(15, 12), .clk_id = {CLK_ETHIF}, - .active_wakeup = true, + .caps = MTK_SCPD_ACTIVE_WAKEUP, }, [MT2701_POWER_DOMAIN_HIF] = { .name = "hif", @@ -584,14 +553,14 @@ static const struct scp_domain_data scp_domain_data_mt2701[] = { .sram_pdn_bits = GENMASK(11, 8), .sram_pdn_ack_bits = GENMASK(15, 12), .clk_id = {CLK_ETHIF}, - .active_wakeup = true, + .caps = MTK_SCPD_ACTIVE_WAKEUP, }, [MT2701_POWER_DOMAIN_IFR_MSC] = { .name = "ifr_msc", .sta_mask = PWR_STATUS_IFR_MSC, .ctl_offs = SPM_IFR_MSC_PWR_CON, .clk_id = {CLK_NONE}, - .active_wakeup = true, + .caps = MTK_SCPD_ACTIVE_WAKEUP, }, }; @@ -606,7 +575,7 @@ static const struct scp_domain_data scp_domain_data_mt2712[] = { .sram_pdn_bits = GENMASK(8, 8), .sram_pdn_ack_bits = GENMASK(12, 12), .clk_id = {CLK_MM}, - .active_wakeup = true, + .caps = MTK_SCPD_ACTIVE_WAKEUP, }, [MT2712_POWER_DOMAIN_VDEC] = { .name = "vdec", @@ -615,7 +584,7 @@ static const struct scp_domain_data scp_domain_data_mt2712[] = { .sram_pdn_bits = GENMASK(8, 8), .sram_pdn_ack_bits = GENMASK(12, 12), .clk_id = {CLK_MM, CLK_VDEC}, - .active_wakeup = true, + .caps = MTK_SCPD_ACTIVE_WAKEUP, }, [MT2712_POWER_DOMAIN_VENC] = { .name = "venc", @@ -624,7 +593,7 @@ static const struct scp_domain_data scp_domain_data_mt2712[] = { .sram_pdn_bits = GENMASK(11, 8), .sram_pdn_ack_bits = GENMASK(15, 12), .clk_id = {CLK_MM, CLK_VENC, CLK_JPGDEC}, - .active_wakeup = true, + .caps = MTK_SCPD_ACTIVE_WAKEUP, }, [MT2712_POWER_DOMAIN_ISP] = { .name = "isp", @@ -633,7 +602,7 @@ static const struct scp_domain_data scp_domain_data_mt2712[] = { .sram_pdn_bits = GENMASK(11, 8), .sram_pdn_ack_bits = GENMASK(13, 12), .clk_id = {CLK_MM}, - .active_wakeup = true, + .caps = MTK_SCPD_ACTIVE_WAKEUP, }, [MT2712_POWER_DOMAIN_AUDIO] = { .name = "audio", @@ -642,7 +611,7 @@ static const struct scp_domain_data scp_domain_data_mt2712[] = { .sram_pdn_bits = GENMASK(11, 8), .sram_pdn_ack_bits = GENMASK(15, 12), .clk_id = {CLK_AUDIO}, - .active_wakeup = true, + .caps = MTK_SCPD_ACTIVE_WAKEUP, }, [MT2712_POWER_DOMAIN_USB] = { .name = "usb", @@ -651,7 +620,7 @@ static const struct scp_domain_data scp_domain_data_mt2712[] = { .sram_pdn_bits = GENMASK(10, 8), .sram_pdn_ack_bits = GENMASK(14, 12), .clk_id = {CLK_NONE}, - .active_wakeup = true, + .caps = MTK_SCPD_ACTIVE_WAKEUP, }, [MT2712_POWER_DOMAIN_USB2] = { .name = "usb2", @@ -660,7 +629,7 @@ static const struct scp_domain_data scp_domain_data_mt2712[] = { .sram_pdn_bits = GENMASK(10, 8), .sram_pdn_ack_bits = GENMASK(14, 12), .clk_id = {CLK_NONE}, - .active_wakeup = true, + .caps = MTK_SCPD_ACTIVE_WAKEUP, }, [MT2712_POWER_DOMAIN_MFG] = { .name = "mfg", @@ -670,7 +639,7 @@ static const struct scp_domain_data scp_domain_data_mt2712[] = { .sram_pdn_ack_bits = GENMASK(16, 16), .clk_id = {CLK_MFG}, .bus_prot_mask = BIT(14) | BIT(21) | BIT(23), - .active_wakeup = true, + .caps = MTK_SCPD_ACTIVE_WAKEUP, }, [MT2712_POWER_DOMAIN_MFG_SC1] = { .name = "mfg_sc1", @@ -679,7 +648,7 @@ static const struct scp_domain_data scp_domain_data_mt2712[] = { .sram_pdn_bits = GENMASK(8, 8), .sram_pdn_ack_bits = GENMASK(16, 16), .clk_id = {CLK_NONE}, - .active_wakeup = true, + .caps = MTK_SCPD_ACTIVE_WAKEUP, }, [MT2712_POWER_DOMAIN_MFG_SC2] = { .name = "mfg_sc2", @@ -688,7 +657,7 @@ static const struct scp_domain_data scp_domain_data_mt2712[] = { .sram_pdn_bits = GENMASK(8, 8), .sram_pdn_ack_bits = GENMASK(16, 16), .clk_id = {CLK_NONE}, - .active_wakeup = true, + .caps = MTK_SCPD_ACTIVE_WAKEUP, }, [MT2712_POWER_DOMAIN_MFG_SC3] = { .name = "mfg_sc3", @@ -697,7 +666,7 @@ static const struct scp_domain_data scp_domain_data_mt2712[] = { .sram_pdn_bits = GENMASK(8, 8), .sram_pdn_ack_bits = GENMASK(16, 16), .clk_id = {CLK_NONE}, - .active_wakeup = true, + .caps = MTK_SCPD_ACTIVE_WAKEUP, }, }; @@ -797,7 +766,7 @@ static const struct scp_domain_data scp_domain_data_mt7622[] = { .sram_pdn_ack_bits = GENMASK(15, 12), .clk_id = {CLK_NONE}, .bus_prot_mask = MT7622_TOP_AXI_PROT_EN_ETHSYS, - .active_wakeup = true, + .caps = MTK_SCPD_ACTIVE_WAKEUP, }, [MT7622_POWER_DOMAIN_HIF0] = { .name = "hif0", @@ -807,7 +776,7 @@ static const struct scp_domain_data scp_domain_data_mt7622[] = { .sram_pdn_ack_bits = GENMASK(15, 12), .clk_id = {CLK_HIFSEL}, .bus_prot_mask = MT7622_TOP_AXI_PROT_EN_HIF0, - .active_wakeup = true, + .caps = MTK_SCPD_ACTIVE_WAKEUP, }, [MT7622_POWER_DOMAIN_HIF1] = { .name = "hif1", @@ -817,7 +786,7 @@ static const struct scp_domain_data scp_domain_data_mt7622[] = { .sram_pdn_ack_bits = GENMASK(15, 12), .clk_id = {CLK_HIFSEL}, .bus_prot_mask = MT7622_TOP_AXI_PROT_EN_HIF1, - .active_wakeup = true, + .caps = MTK_SCPD_ACTIVE_WAKEUP, }, [MT7622_POWER_DOMAIN_WB] = { .name = "wb", @@ -827,7 +796,7 @@ static const struct scp_domain_data scp_domain_data_mt7622[] = { .sram_pdn_ack_bits = 0, .clk_id = {CLK_NONE}, .bus_prot_mask = MT7622_TOP_AXI_PROT_EN_WB, - .active_wakeup = true, + .caps = MTK_SCPD_ACTIVE_WAKEUP | MTK_SCPD_FWAIT_SRAM, }, }; @@ -843,7 +812,7 @@ static const struct scp_domain_data scp_domain_data_mt7623a[] = { .bus_prot_mask = MT2701_TOP_AXI_PROT_EN_CONN_M | MT2701_TOP_AXI_PROT_EN_CONN_S, .clk_id = {CLK_NONE}, - .active_wakeup = true, + .caps = MTK_SCPD_ACTIVE_WAKEUP, }, [MT7623A_POWER_DOMAIN_ETH] = { .name = "eth", @@ -852,7 +821,7 @@ static const struct scp_domain_data scp_domain_data_mt7623a[] = { .sram_pdn_bits = GENMASK(11, 8), .sram_pdn_ack_bits = GENMASK(15, 12), .clk_id = {CLK_ETHIF}, - .active_wakeup = true, + .caps = MTK_SCPD_ACTIVE_WAKEUP, }, [MT7623A_POWER_DOMAIN_HIF] = { .name = "hif", @@ -861,14 +830,14 @@ static const struct scp_domain_data scp_domain_data_mt7623a[] = { .sram_pdn_bits = GENMASK(11, 8), .sram_pdn_ack_bits = GENMASK(15, 12), .clk_id = {CLK_ETHIF}, - .active_wakeup = true, + .caps = MTK_SCPD_ACTIVE_WAKEUP, }, [MT7623A_POWER_DOMAIN_IFR_MSC] = { .name = "ifr_msc", .sta_mask = PWR_STATUS_IFR_MSC, .ctl_offs = SPM_IFR_MSC_PWR_CON, .clk_id = {CLK_NONE}, - .active_wakeup = true, + .caps = MTK_SCPD_ACTIVE_WAKEUP, }, }; @@ -934,7 +903,7 @@ static const struct scp_domain_data scp_domain_data_mt8173[] = { .sram_pdn_bits = GENMASK(11, 8), .sram_pdn_ack_bits = GENMASK(15, 12), .clk_id = {CLK_NONE}, - .active_wakeup = true, + .caps = MTK_SCPD_ACTIVE_WAKEUP, }, [MT8173_POWER_DOMAIN_MFG_ASYNC] = { .name = "mfg_async", @@ -1067,15 +1036,13 @@ static const struct of_device_id of_scpsys_match_tbl[] = { static int scpsys_probe(struct platform_device *pdev) { - const struct of_device_id *match; const struct scp_subdomain *sd; const struct scp_soc_data *soc; struct scp *scp; struct genpd_onecell_data *pd_data; int i, ret; - match = of_match_device(of_scpsys_match_tbl, &pdev->dev); - soc = (const struct scp_soc_data *)match->data; + soc = of_device_get_match_data(&pdev->dev); scp = init_scp(pdev, soc->domains, soc->num_domains, &soc->regs, soc->bus_prot_reg_update); diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index d053f2634c67..9dc02f390ba3 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -3,6 +3,24 @@ # menu "Qualcomm SoC drivers" +config QCOM_COMMAND_DB + bool "Qualcomm Command DB" + depends on (ARCH_QCOM && OF) || COMPILE_TEST + help + Command DB queries shared memory by key string for shared system + resources. Platform drivers that require to set state of a shared + resource on a RPM-hardened platform must use this database to get + SoC specific identifier and information for the shared resources. + +config QCOM_GENI_SE + tristate "QCOM GENI Serial Engine Driver" + depends on ARCH_QCOM || COMPILE_TEST + help + This driver is used to manage Generic Interface (GENI) firmware based + Qualcomm Technologies, Inc. Universal Peripheral (QUP) Wrapper. This + driver is also used to manage the common aspects of multiple Serial + Engines present in the QUP. + config QCOM_GLINK_SSR tristate "Qualcomm Glink SSR driver" depends on RPMSG diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 39de5dee55d9..19dcf957cb3a 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -1,4 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_QCOM_GENI_SE) += qcom-geni-se.o +obj-$(CONFIG_QCOM_COMMAND_DB) += cmd-db.o obj-$(CONFIG_QCOM_GLINK_SSR) += glink_ssr.o obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o obj-$(CONFIG_QCOM_MDT_LOADER) += mdt_loader.o diff --git a/drivers/soc/qcom/cmd-db.c b/drivers/soc/qcom/cmd-db.c new file mode 100644 index 000000000000..a6f646295f06 --- /dev/null +++ b/drivers/soc/qcom/cmd-db.c @@ -0,0 +1,317 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. */ + +#include <linux/kernel.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_platform.h> +#include <linux/of_reserved_mem.h> +#include <linux/platform_device.h> +#include <linux/types.h> + +#include <soc/qcom/cmd-db.h> + +#define NUM_PRIORITY 2 +#define MAX_SLV_ID 8 +#define SLAVE_ID_MASK 0x7 +#define SLAVE_ID_SHIFT 16 + +/** + * struct entry_header: header for each entry in cmddb + * + * @id: resource's identifier + * @priority: unused + * @addr: the address of the resource + * @len: length of the data + * @offset: offset from :@data_offset, start of the data + */ +struct entry_header { + u8 id[8]; + __le32 priority[NUM_PRIORITY]; + __le32 addr; + __le16 len; + __le16 offset; +}; + +/** + * struct rsc_hdr: resource header information + * + * @slv_id: id for the resource + * @header_offset: entry's header at offset from the end of the cmd_db_header + * @data_offset: entry's data at offset from the end of the cmd_db_header + * @cnt: number of entries for HW type + * @version: MSB is major, LSB is minor + * @reserved: reserved for future use. + */ +struct rsc_hdr { + __le16 slv_id; + __le16 header_offset; + __le16 data_offset; + __le16 cnt; + __le16 version; + __le16 reserved[3]; +}; + +/** + * struct cmd_db_header: The DB header information + * + * @version: The cmd db version + * @magic: constant expected in the database + * @header: array of resources + * @checksum: checksum for the header. Unused. + * @reserved: reserved memory + * @data: driver specific data + */ +struct cmd_db_header { + __le32 version; + u8 magic[4]; + struct rsc_hdr header[MAX_SLV_ID]; + __le32 checksum; + __le32 reserved; + u8 data[]; +}; + +/** + * DOC: Description of the Command DB database. + * + * At the start of the command DB memory is the cmd_db_header structure. + * The cmd_db_header holds the version, checksum, magic key as well as an + * array for header for each slave (depicted by the rsc_header). Each h/w + * based accelerator is a 'slave' (shared resource) and has slave id indicating + * the type of accelerator. The rsc_header is the header for such individual + * slaves of a given type. The entries for each of these slaves begin at the + * rsc_hdr.header_offset. In addition each slave could have auxiliary data + * that may be needed by the driver. The data for the slave starts at the + * entry_header.offset to the location pointed to by the rsc_hdr.data_offset. + * + * Drivers have a stringified key to a slave/resource. They can query the slave + * information and get the slave id and the auxiliary data and the length of the + * data. Using this information, they can format the request to be sent to the + * h/w accelerator and request a resource state. + */ + +static const u8 CMD_DB_MAGIC[] = { 0xdb, 0x30, 0x03, 0x0c }; + +static bool cmd_db_magic_matches(const struct cmd_db_header *header) +{ + const u8 *magic = header->magic; + + return memcmp(magic, CMD_DB_MAGIC, ARRAY_SIZE(CMD_DB_MAGIC)) == 0; +} + +static struct cmd_db_header *cmd_db_header; + + +static inline void *rsc_to_entry_header(struct rsc_hdr *hdr) +{ + u16 offset = le16_to_cpu(hdr->header_offset); + + return cmd_db_header->data + offset; +} + +static inline void * +rsc_offset(struct rsc_hdr *hdr, struct entry_header *ent) +{ + u16 offset = le16_to_cpu(hdr->data_offset); + u16 loffset = le16_to_cpu(ent->offset); + + return cmd_db_header->data + offset + loffset; +} + +/** + * cmd_db_ready - Indicates if command DB is available + * + * Return: 0 on success, errno otherwise + */ +int cmd_db_ready(void) +{ + if (cmd_db_header == NULL) + return -EPROBE_DEFER; + else if (!cmd_db_magic_matches(cmd_db_header)) + return -EINVAL; + + return 0; +} +EXPORT_SYMBOL(cmd_db_ready); + +static int cmd_db_get_header(const char *id, struct entry_header *eh, + struct rsc_hdr *rh) +{ + struct rsc_hdr *rsc_hdr; + struct entry_header *ent; + int ret, i, j; + u8 query[8]; + + ret = cmd_db_ready(); + if (ret) + return ret; + + if (!eh || !rh) + return -EINVAL; + + /* Pad out query string to same length as in DB */ + strncpy(query, id, sizeof(query)); + + for (i = 0; i < MAX_SLV_ID; i++) { + rsc_hdr = &cmd_db_header->header[i]; + if (!rsc_hdr->slv_id) + break; + + ent = rsc_to_entry_header(rsc_hdr); + for (j = 0; j < le16_to_cpu(rsc_hdr->cnt); j++, ent++) { + if (memcmp(ent->id, query, sizeof(ent->id)) == 0) + break; + } + + if (j < le16_to_cpu(rsc_hdr->cnt)) { + memcpy(eh, ent, sizeof(*ent)); + memcpy(rh, rsc_hdr, sizeof(*rh)); + return 0; + } + } + + return -ENODEV; +} + +/** + * cmd_db_read_addr() - Query command db for resource id address. + * + * @id: resource id to query for address + * + * Return: resource address on success, 0 on error + * + * This is used to retrieve resource address based on resource + * id. + */ +u32 cmd_db_read_addr(const char *id) +{ + int ret; + struct entry_header ent; + struct rsc_hdr rsc_hdr; + + ret = cmd_db_get_header(id, &ent, &rsc_hdr); + + return ret < 0 ? 0 : le32_to_cpu(ent.addr); +} +EXPORT_SYMBOL(cmd_db_read_addr); + +/** + * cmd_db_read_aux_data() - Query command db for aux data. + * + * @id: Resource to retrieve AUX Data on. + * @data: Data buffer to copy returned aux data to. Returns size on NULL + * @len: Caller provides size of data buffer passed in. + * + * Return: size of data on success, errno otherwise + */ +int cmd_db_read_aux_data(const char *id, u8 *data, size_t len) +{ + int ret; + struct entry_header ent; + struct rsc_hdr rsc_hdr; + u16 ent_len; + + if (!data) + return -EINVAL; + + ret = cmd_db_get_header(id, &ent, &rsc_hdr); + if (ret) + return ret; + + ent_len = le16_to_cpu(ent.len); + if (len < ent_len) + return -EINVAL; + + len = min_t(u16, ent_len, len); + memcpy(data, rsc_offset(&rsc_hdr, &ent), len); + + return len; +} +EXPORT_SYMBOL(cmd_db_read_aux_data); + +/** + * cmd_db_read_aux_data_len - Get the length of the auxiliary data stored in DB. + * + * @id: Resource to retrieve AUX Data. + * + * Return: size on success, 0 on error + */ +size_t cmd_db_read_aux_data_len(const char *id) +{ + int ret; + struct entry_header ent; + struct rsc_hdr rsc_hdr; + + ret = cmd_db_get_header(id, &ent, &rsc_hdr); + + return ret < 0 ? 0 : le16_to_cpu(ent.len); +} +EXPORT_SYMBOL(cmd_db_read_aux_data_len); + +/** + * cmd_db_read_slave_id - Get the slave ID for a given resource address + * + * @id: Resource id to query the DB for version + * + * Return: cmd_db_hw_type enum on success, CMD_DB_HW_INVALID on error + */ +enum cmd_db_hw_type cmd_db_read_slave_id(const char *id) +{ + int ret; + struct entry_header ent; + struct rsc_hdr rsc_hdr; + u32 addr; + + ret = cmd_db_get_header(id, &ent, &rsc_hdr); + if (ret < 0) + return CMD_DB_HW_INVALID; + + addr = le32_to_cpu(ent.addr); + return (addr >> SLAVE_ID_SHIFT) & SLAVE_ID_MASK; +} +EXPORT_SYMBOL(cmd_db_read_slave_id); + +static int cmd_db_dev_probe(struct platform_device *pdev) +{ + struct reserved_mem *rmem; + int ret = 0; + + rmem = of_reserved_mem_lookup(pdev->dev.of_node); + if (!rmem) { + dev_err(&pdev->dev, "failed to acquire memory region\n"); + return -EINVAL; + } + + cmd_db_header = memremap(rmem->base, rmem->size, MEMREMAP_WB); + if (IS_ERR_OR_NULL(cmd_db_header)) { + ret = PTR_ERR(cmd_db_header); + cmd_db_header = NULL; + return ret; + } + + if (!cmd_db_magic_matches(cmd_db_header)) { + dev_err(&pdev->dev, "Invalid Command DB Magic\n"); + return -EINVAL; + } + + return 0; +} + +static const struct of_device_id cmd_db_match_table[] = { + { .compatible = "qcom,cmd-db" }, + { }, +}; + +static struct platform_driver cmd_db_dev_driver = { + .probe = cmd_db_dev_probe, + .driver = { + .name = "cmd-db", + .of_match_table = cmd_db_match_table, + }, +}; + +static int __init cmd_db_device_init(void) +{ + return platform_driver_register(&cmd_db_dev_driver); +} +arch_initcall(cmd_db_device_init); diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c index 17b314d9a148..dc09d7ac905f 100644 --- a/drivers/soc/qcom/mdt_loader.c +++ b/drivers/soc/qcom/mdt_loader.c @@ -50,7 +50,7 @@ ssize_t qcom_mdt_get_size(const struct firmware *fw) const struct elf32_phdr *phdrs; const struct elf32_phdr *phdr; const struct elf32_hdr *ehdr; - phys_addr_t min_addr = (phys_addr_t)ULLONG_MAX; + phys_addr_t min_addr = PHYS_ADDR_MAX; phys_addr_t max_addr = 0; int i; @@ -97,7 +97,7 @@ int qcom_mdt_load(struct device *dev, const struct firmware *fw, const struct elf32_hdr *ehdr; const struct firmware *seg_fw; phys_addr_t mem_reloc; - phys_addr_t min_addr = (phys_addr_t)ULLONG_MAX; + phys_addr_t min_addr = PHYS_ADDR_MAX; phys_addr_t max_addr = 0; size_t fw_name_len; ssize_t offset; diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c new file mode 100644 index 000000000000..feed3db21c10 --- /dev/null +++ b/drivers/soc/qcom/qcom-geni-se.c @@ -0,0 +1,748 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + +#include <linux/clk.h> +#include <linux/slab.h> +#include <linux/dma-mapping.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/pinctrl/consumer.h> +#include <linux/platform_device.h> +#include <linux/qcom-geni-se.h> + +/** + * DOC: Overview + * + * Generic Interface (GENI) Serial Engine (SE) Wrapper driver is introduced + * to manage GENI firmware based Qualcomm Universal Peripheral (QUP) Wrapper + * controller. QUP Wrapper is designed to support various serial bus protocols + * like UART, SPI, I2C, I3C, etc. + */ + +/** + * DOC: Hardware description + * + * GENI based QUP is a highly-flexible and programmable module for supporting + * a wide range of serial interfaces like UART, SPI, I2C, I3C, etc. A single + * QUP module can provide upto 8 serial interfaces, using its internal + * serial engines. The actual configuration is determined by the target + * platform configuration. The protocol supported by each interface is + * determined by the firmware loaded to the serial engine. Each SE consists + * of a DMA Engine and GENI sub modules which enable serial engines to + * support FIFO and DMA modes of operation. + * + * + * +-----------------------------------------+ + * |QUP Wrapper | + * | +----------------------------+ | + * --QUP & SE Clocks--> | Serial Engine N | +-IO------> + * | | ... | | Interface + * <---Clock Perf.----+ +----+-----------------------+ | | + * State Interface | | Serial Engine 1 | | | + * | | | | | + * | | | | | + * <--------AHB-------> | | | | + * | | +----+ | + * | | | | + * | | | | + * <------SE IRQ------+ +----------------------------+ | + * | | + * +-----------------------------------------+ + * + * Figure 1: GENI based QUP Wrapper + * + * The GENI submodules include primary and secondary sequencers which are + * used to drive TX & RX operations. On serial interfaces that operate using + * master-slave model, primary sequencer drives both TX & RX operations. On + * serial interfaces that operate using peer-to-peer model, primary sequencer + * drives TX operation and secondary sequencer drives RX operation. + */ + +/** + * DOC: Software description + * + * GENI SE Wrapper driver is structured into 2 parts: + * + * geni_wrapper represents QUP Wrapper controller. This part of the driver + * manages QUP Wrapper information such as hardware version, clock + * performance table that is common to all the internal serial engines. + * + * geni_se represents serial engine. This part of the driver manages serial + * engine information such as clocks, containing QUP Wrapper, etc. This part + * of driver also supports operations (eg. initialize the concerned serial + * engine, select between FIFO and DMA mode of operation etc.) that are + * common to all the serial engines and are independent of serial interfaces. + */ + +#define MAX_CLK_PERF_LEVEL 32 +#define NUM_AHB_CLKS 2 + +/** + * @struct geni_wrapper - Data structure to represent the QUP Wrapper Core + * @dev: Device pointer of the QUP wrapper core + * @base: Base address of this instance of QUP wrapper core + * @ahb_clks: Handle to the primary & secondary AHB clocks + */ +struct geni_wrapper { + struct device *dev; + void __iomem *base; + struct clk_bulk_data ahb_clks[NUM_AHB_CLKS]; +}; + +#define QUP_HW_VER_REG 0x4 + +/* Common SE registers */ +#define GENI_INIT_CFG_REVISION 0x0 +#define GENI_S_INIT_CFG_REVISION 0x4 +#define GENI_OUTPUT_CTRL 0x24 +#define GENI_CGC_CTRL 0x28 +#define GENI_CLK_CTRL_RO 0x60 +#define GENI_IF_DISABLE_RO 0x64 +#define GENI_FW_S_REVISION_RO 0x6c +#define SE_GENI_BYTE_GRAN 0x254 +#define SE_GENI_TX_PACKING_CFG0 0x260 +#define SE_GENI_TX_PACKING_CFG1 0x264 +#define SE_GENI_RX_PACKING_CFG0 0x284 +#define SE_GENI_RX_PACKING_CFG1 0x288 +#define SE_GENI_M_GP_LENGTH 0x910 +#define SE_GENI_S_GP_LENGTH 0x914 +#define SE_DMA_TX_PTR_L 0xc30 +#define SE_DMA_TX_PTR_H 0xc34 +#define SE_DMA_TX_ATTR 0xc38 +#define SE_DMA_TX_LEN 0xc3c +#define SE_DMA_TX_IRQ_EN 0xc48 +#define SE_DMA_TX_IRQ_EN_SET 0xc4c +#define SE_DMA_TX_IRQ_EN_CLR 0xc50 +#define SE_DMA_TX_LEN_IN 0xc54 +#define SE_DMA_TX_MAX_BURST 0xc5c +#define SE_DMA_RX_PTR_L 0xd30 +#define SE_DMA_RX_PTR_H 0xd34 +#define SE_DMA_RX_ATTR 0xd38 +#define SE_DMA_RX_LEN 0xd3c +#define SE_DMA_RX_IRQ_EN 0xd48 +#define SE_DMA_RX_IRQ_EN_SET 0xd4c +#define SE_DMA_RX_IRQ_EN_CLR 0xd50 +#define SE_DMA_RX_LEN_IN 0xd54 +#define SE_DMA_RX_MAX_BURST 0xd5c +#define SE_DMA_RX_FLUSH 0xd60 +#define SE_GSI_EVENT_EN 0xe18 +#define SE_IRQ_EN 0xe1c +#define SE_DMA_GENERAL_CFG 0xe30 + +/* GENI_OUTPUT_CTRL fields */ +#define DEFAULT_IO_OUTPUT_CTRL_MSK GENMASK(6, 0) + +/* GENI_CGC_CTRL fields */ +#define CFG_AHB_CLK_CGC_ON BIT(0) +#define CFG_AHB_WR_ACLK_CGC_ON BIT(1) +#define DATA_AHB_CLK_CGC_ON BIT(2) +#define SCLK_CGC_ON BIT(3) +#define TX_CLK_CGC_ON BIT(4) +#define RX_CLK_CGC_ON BIT(5) +#define EXT_CLK_CGC_ON BIT(6) +#define PROG_RAM_HCLK_OFF BIT(8) +#define PROG_RAM_SCLK_OFF BIT(9) +#define DEFAULT_CGC_EN GENMASK(6, 0) + +/* SE_GSI_EVENT_EN fields */ +#define DMA_RX_EVENT_EN BIT(0) +#define DMA_TX_EVENT_EN BIT(1) +#define GENI_M_EVENT_EN BIT(2) +#define GENI_S_EVENT_EN BIT(3) + +/* SE_IRQ_EN fields */ +#define DMA_RX_IRQ_EN BIT(0) +#define DMA_TX_IRQ_EN BIT(1) +#define GENI_M_IRQ_EN BIT(2) +#define GENI_S_IRQ_EN BIT(3) + +/* SE_DMA_GENERAL_CFG */ +#define DMA_RX_CLK_CGC_ON BIT(0) +#define DMA_TX_CLK_CGC_ON BIT(1) +#define DMA_AHB_SLV_CFG_ON BIT(2) +#define AHB_SEC_SLV_CLK_CGC_ON BIT(3) +#define DUMMY_RX_NON_BUFFERABLE BIT(4) +#define RX_DMA_ZERO_PADDING_EN BIT(5) +#define RX_DMA_IRQ_DELAY_MSK GENMASK(8, 6) +#define RX_DMA_IRQ_DELAY_SHFT 6 + +/** + * geni_se_get_qup_hw_version() - Read the QUP wrapper Hardware version + * @se: Pointer to the corresponding serial engine. + * + * Return: Hardware Version of the wrapper. + */ +u32 geni_se_get_qup_hw_version(struct geni_se *se) +{ + struct geni_wrapper *wrapper = se->wrapper; + + return readl_relaxed(wrapper->base + QUP_HW_VER_REG); +} +EXPORT_SYMBOL(geni_se_get_qup_hw_version); + +static void geni_se_io_set_mode(void __iomem *base) +{ + u32 val; + + val = readl_relaxed(base + SE_IRQ_EN); + val |= GENI_M_IRQ_EN | GENI_S_IRQ_EN; + val |= DMA_TX_IRQ_EN | DMA_RX_IRQ_EN; + writel_relaxed(val, base + SE_IRQ_EN); + + val = readl_relaxed(base + SE_GENI_DMA_MODE_EN); + val &= ~GENI_DMA_MODE_EN; + writel_relaxed(val, base + SE_GENI_DMA_MODE_EN); + + writel_relaxed(0, base + SE_GSI_EVENT_EN); +} + +static void geni_se_io_init(void __iomem *base) +{ + u32 val; + + val = readl_relaxed(base + GENI_CGC_CTRL); + val |= DEFAULT_CGC_EN; + writel_relaxed(val, base + GENI_CGC_CTRL); + + val = readl_relaxed(base + SE_DMA_GENERAL_CFG); + val |= AHB_SEC_SLV_CLK_CGC_ON | DMA_AHB_SLV_CFG_ON; + val |= DMA_TX_CLK_CGC_ON | DMA_RX_CLK_CGC_ON; + writel_relaxed(val, base + SE_DMA_GENERAL_CFG); + + writel_relaxed(DEFAULT_IO_OUTPUT_CTRL_MSK, base + GENI_OUTPUT_CTRL); + writel_relaxed(FORCE_DEFAULT, base + GENI_FORCE_DEFAULT_REG); +} + +/** + * geni_se_init() - Initialize the GENI serial engine + * @se: Pointer to the concerned serial engine. + * @rx_wm: Receive watermark, in units of FIFO words. + * @rx_rfr_wm: Ready-for-receive watermark, in units of FIFO words. + * + * This function is used to initialize the GENI serial engine, configure + * receive watermark and ready-for-receive watermarks. + */ +void geni_se_init(struct geni_se *se, u32 rx_wm, u32 rx_rfr) +{ + u32 val; + + geni_se_io_init(se->base); + geni_se_io_set_mode(se->base); + + writel_relaxed(rx_wm, se->base + SE_GENI_RX_WATERMARK_REG); + writel_relaxed(rx_rfr, se->base + SE_GENI_RX_RFR_WATERMARK_REG); + + val = readl_relaxed(se->base + SE_GENI_M_IRQ_EN); + val |= M_COMMON_GENI_M_IRQ_EN; + writel_relaxed(val, se->base + SE_GENI_M_IRQ_EN); + + val = readl_relaxed(se->base + SE_GENI_S_IRQ_EN); + val |= S_COMMON_GENI_S_IRQ_EN; + writel_relaxed(val, se->base + SE_GENI_S_IRQ_EN); +} +EXPORT_SYMBOL(geni_se_init); + +static void geni_se_select_fifo_mode(struct geni_se *se) +{ + u32 proto = geni_se_read_proto(se); + u32 val; + + writel_relaxed(0, se->base + SE_GSI_EVENT_EN); + writel_relaxed(0xffffffff, se->base + SE_GENI_M_IRQ_CLEAR); + writel_relaxed(0xffffffff, se->base + SE_GENI_S_IRQ_CLEAR); + writel_relaxed(0xffffffff, se->base + SE_DMA_TX_IRQ_CLR); + writel_relaxed(0xffffffff, se->base + SE_DMA_RX_IRQ_CLR); + writel_relaxed(0xffffffff, se->base + SE_IRQ_EN); + + val = readl_relaxed(se->base + SE_GENI_M_IRQ_EN); + if (proto != GENI_SE_UART) { + val |= M_CMD_DONE_EN | M_TX_FIFO_WATERMARK_EN; + val |= M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN; + } + writel_relaxed(val, se->base + SE_GENI_M_IRQ_EN); + + val = readl_relaxed(se->base + SE_GENI_S_IRQ_EN); + if (proto != GENI_SE_UART) + val |= S_CMD_DONE_EN; + writel_relaxed(val, se->base + SE_GENI_S_IRQ_EN); + + val = readl_relaxed(se->base + SE_GENI_DMA_MODE_EN); + val &= ~GENI_DMA_MODE_EN; + writel_relaxed(val, se->base + SE_GENI_DMA_MODE_EN); +} + +static void geni_se_select_dma_mode(struct geni_se *se) +{ + u32 val; + + writel_relaxed(0, se->base + SE_GSI_EVENT_EN); + writel_relaxed(0xffffffff, se->base + SE_GENI_M_IRQ_CLEAR); + writel_relaxed(0xffffffff, se->base + SE_GENI_S_IRQ_CLEAR); + writel_relaxed(0xffffffff, se->base + SE_DMA_TX_IRQ_CLR); + writel_relaxed(0xffffffff, se->base + SE_DMA_RX_IRQ_CLR); + writel_relaxed(0xffffffff, se->base + SE_IRQ_EN); + + val = readl_relaxed(se->base + SE_GENI_DMA_MODE_EN); + val |= GENI_DMA_MODE_EN; + writel_relaxed(val, se->base + SE_GENI_DMA_MODE_EN); +} + +/** + * geni_se_select_mode() - Select the serial engine transfer mode + * @se: Pointer to the concerned serial engine. + * @mode: Transfer mode to be selected. + */ +void geni_se_select_mode(struct geni_se *se, enum geni_se_xfer_mode mode) +{ + WARN_ON(mode != GENI_SE_FIFO && mode != GENI_SE_DMA); + + switch (mode) { + case GENI_SE_FIFO: + geni_se_select_fifo_mode(se); + break; + case GENI_SE_DMA: + geni_se_select_dma_mode(se); + break; + case GENI_SE_INVALID: + default: + break; + } +} +EXPORT_SYMBOL(geni_se_select_mode); + +/** + * DOC: Overview + * + * GENI FIFO packing is highly configurable. TX/RX packing/unpacking consist + * of up to 4 operations, each operation represented by 4 configuration vectors + * of 10 bits programmed in GENI_TX_PACKING_CFG0 and GENI_TX_PACKING_CFG1 for + * TX FIFO and in GENI_RX_PACKING_CFG0 and GENI_RX_PACKING_CFG1 for RX FIFO. + * Refer to below examples for detailed bit-field description. + * + * Example 1: word_size = 7, packing_mode = 4 x 8, msb_to_lsb = 1 + * + * +-----------+-------+-------+-------+-------+ + * | | vec_0 | vec_1 | vec_2 | vec_3 | + * +-----------+-------+-------+-------+-------+ + * | start | 0x6 | 0xe | 0x16 | 0x1e | + * | direction | 1 | 1 | 1 | 1 | + * | length | 6 | 6 | 6 | 6 | + * | stop | 0 | 0 | 0 | 1 | + * +-----------+-------+-------+-------+-------+ + * + * Example 2: word_size = 15, packing_mode = 2 x 16, msb_to_lsb = 0 + * + * +-----------+-------+-------+-------+-------+ + * | | vec_0 | vec_1 | vec_2 | vec_3 | + * +-----------+-------+-------+-------+-------+ + * | start | 0x0 | 0x8 | 0x10 | 0x18 | + * | direction | 0 | 0 | 0 | 0 | + * | length | 7 | 6 | 7 | 6 | + * | stop | 0 | 0 | 0 | 1 | + * +-----------+-------+-------+-------+-------+ + * + * Example 3: word_size = 23, packing_mode = 1 x 32, msb_to_lsb = 1 + * + * +-----------+-------+-------+-------+-------+ + * | | vec_0 | vec_1 | vec_2 | vec_3 | + * +-----------+-------+-------+-------+-------+ + * | start | 0x16 | 0xe | 0x6 | 0x0 | + * | direction | 1 | 1 | 1 | 1 | + * | length | 7 | 7 | 6 | 0 | + * | stop | 0 | 0 | 1 | 0 | + * +-----------+-------+-------+-------+-------+ + * + */ + +#define NUM_PACKING_VECTORS 4 +#define PACKING_START_SHIFT 5 +#define PACKING_DIR_SHIFT 4 +#define PACKING_LEN_SHIFT 1 +#define PACKING_STOP_BIT BIT(0) +#define PACKING_VECTOR_SHIFT 10 +/** + * geni_se_config_packing() - Packing configuration of the serial engine + * @se: Pointer to the concerned serial engine + * @bpw: Bits of data per transfer word. + * @pack_words: Number of words per fifo element. + * @msb_to_lsb: Transfer from MSB to LSB or vice-versa. + * @tx_cfg: Flag to configure the TX Packing. + * @rx_cfg: Flag to configure the RX Packing. + * + * This function is used to configure the packing rules for the current + * transfer. + */ +void geni_se_config_packing(struct geni_se *se, int bpw, int pack_words, + bool msb_to_lsb, bool tx_cfg, bool rx_cfg) +{ + u32 cfg0, cfg1, cfg[NUM_PACKING_VECTORS] = {0}; + int len; + int temp_bpw = bpw; + int idx_start = msb_to_lsb ? bpw - 1 : 0; + int idx = idx_start; + int idx_delta = msb_to_lsb ? -BITS_PER_BYTE : BITS_PER_BYTE; + int ceil_bpw = ALIGN(bpw, BITS_PER_BYTE); + int iter = (ceil_bpw * pack_words) / BITS_PER_BYTE; + int i; + + if (iter <= 0 || iter > NUM_PACKING_VECTORS) + return; + + for (i = 0; i < iter; i++) { + len = min_t(int, temp_bpw, BITS_PER_BYTE) - 1; + cfg[i] = idx << PACKING_START_SHIFT; + cfg[i] |= msb_to_lsb << PACKING_DIR_SHIFT; + cfg[i] |= len << PACKING_LEN_SHIFT; + + if (temp_bpw <= BITS_PER_BYTE) { + idx = ((i + 1) * BITS_PER_BYTE) + idx_start; + temp_bpw = bpw; + } else { + idx = idx + idx_delta; + temp_bpw = temp_bpw - BITS_PER_BYTE; + } + } + cfg[iter - 1] |= PACKING_STOP_BIT; + cfg0 = cfg[0] | (cfg[1] << PACKING_VECTOR_SHIFT); + cfg1 = cfg[2] | (cfg[3] << PACKING_VECTOR_SHIFT); + + if (tx_cfg) { + writel_relaxed(cfg0, se->base + SE_GENI_TX_PACKING_CFG0); + writel_relaxed(cfg1, se->base + SE_GENI_TX_PACKING_CFG1); + } + if (rx_cfg) { + writel_relaxed(cfg0, se->base + SE_GENI_RX_PACKING_CFG0); + writel_relaxed(cfg1, se->base + SE_GENI_RX_PACKING_CFG1); + } + + /* + * Number of protocol words in each FIFO entry + * 0 - 4x8, four words in each entry, max word size of 8 bits + * 1 - 2x16, two words in each entry, max word size of 16 bits + * 2 - 1x32, one word in each entry, max word size of 32 bits + * 3 - undefined + */ + if (pack_words || bpw == 32) + writel_relaxed(bpw / 16, se->base + SE_GENI_BYTE_GRAN); +} +EXPORT_SYMBOL(geni_se_config_packing); + +static void geni_se_clks_off(struct geni_se *se) +{ + struct geni_wrapper *wrapper = se->wrapper; + + clk_disable_unprepare(se->clk); + clk_bulk_disable_unprepare(ARRAY_SIZE(wrapper->ahb_clks), + wrapper->ahb_clks); +} + +/** + * geni_se_resources_off() - Turn off resources associated with the serial + * engine + * @se: Pointer to the concerned serial engine. + * + * Return: 0 on success, standard Linux error codes on failure/error. + */ +int geni_se_resources_off(struct geni_se *se) +{ + int ret; + + ret = pinctrl_pm_select_sleep_state(se->dev); + if (ret) + return ret; + + geni_se_clks_off(se); + return 0; +} +EXPORT_SYMBOL(geni_se_resources_off); + +static int geni_se_clks_on(struct geni_se *se) +{ + int ret; + struct geni_wrapper *wrapper = se->wrapper; + + ret = clk_bulk_prepare_enable(ARRAY_SIZE(wrapper->ahb_clks), + wrapper->ahb_clks); + if (ret) + return ret; + + ret = clk_prepare_enable(se->clk); + if (ret) + clk_bulk_disable_unprepare(ARRAY_SIZE(wrapper->ahb_clks), + wrapper->ahb_clks); + return ret; +} + +/** + * geni_se_resources_on() - Turn on resources associated with the serial + * engine + * @se: Pointer to the concerned serial engine. + * + * Return: 0 on success, standard Linux error codes on failure/error. + */ +int geni_se_resources_on(struct geni_se *se) +{ + int ret; + + ret = geni_se_clks_on(se); + if (ret) + return ret; + + ret = pinctrl_pm_select_default_state(se->dev); + if (ret) + geni_se_clks_off(se); + + return ret; +} +EXPORT_SYMBOL(geni_se_resources_on); + +/** + * geni_se_clk_tbl_get() - Get the clock table to program DFS + * @se: Pointer to the concerned serial engine. + * @tbl: Table in which the output is returned. + * + * This function is called by the protocol drivers to determine the different + * clock frequencies supported by serial engine core clock. The protocol + * drivers use the output to determine the clock frequency index to be + * programmed into DFS. + * + * Return: number of valid performance levels in the table on success, + * standard Linux error codes on failure. + */ +int geni_se_clk_tbl_get(struct geni_se *se, unsigned long **tbl) +{ + unsigned long freq = 0; + int i; + + if (se->clk_perf_tbl) { + *tbl = se->clk_perf_tbl; + return se->num_clk_levels; + } + + se->clk_perf_tbl = devm_kcalloc(se->dev, MAX_CLK_PERF_LEVEL, + sizeof(*se->clk_perf_tbl), + GFP_KERNEL); + if (!se->clk_perf_tbl) + return -ENOMEM; + + for (i = 0; i < MAX_CLK_PERF_LEVEL; i++) { + freq = clk_round_rate(se->clk, freq + 1); + if (!freq || freq == se->clk_perf_tbl[i - 1]) + break; + se->clk_perf_tbl[i] = freq; + } + se->num_clk_levels = i; + *tbl = se->clk_perf_tbl; + return se->num_clk_levels; +} +EXPORT_SYMBOL(geni_se_clk_tbl_get); + +/** + * geni_se_clk_freq_match() - Get the matching or closest SE clock frequency + * @se: Pointer to the concerned serial engine. + * @req_freq: Requested clock frequency. + * @index: Index of the resultant frequency in the table. + * @res_freq: Resultant frequency which matches or is closer to the + * requested frequency. + * @exact: Flag to indicate exact multiple requirement of the requested + * frequency. + * + * This function is called by the protocol drivers to determine the matching + * or exact multiple of the requested frequency, as provided by the serial + * engine clock in order to meet the performance requirements. If there is + * no matching or exact multiple of the requested frequency found, then it + * selects the closest floor frequency, if exact flag is not set. + * + * Return: 0 on success, standard Linux error codes on failure. + */ +int geni_se_clk_freq_match(struct geni_se *se, unsigned long req_freq, + unsigned int *index, unsigned long *res_freq, + bool exact) +{ + unsigned long *tbl; + int num_clk_levels; + int i; + + num_clk_levels = geni_se_clk_tbl_get(se, &tbl); + if (num_clk_levels < 0) + return num_clk_levels; + + if (num_clk_levels == 0) + return -EINVAL; + + *res_freq = 0; + for (i = 0; i < num_clk_levels; i++) { + if (!(tbl[i] % req_freq)) { + *index = i; + *res_freq = tbl[i]; + return 0; + } + + if (!(*res_freq) || ((tbl[i] > *res_freq) && + (tbl[i] < req_freq))) { + *index = i; + *res_freq = tbl[i]; + } + } + + if (exact) + return -EINVAL; + + return 0; +} +EXPORT_SYMBOL(geni_se_clk_freq_match); + +#define GENI_SE_DMA_DONE_EN BIT(0) +#define GENI_SE_DMA_EOT_EN BIT(1) +#define GENI_SE_DMA_AHB_ERR_EN BIT(2) +#define GENI_SE_DMA_EOT_BUF BIT(0) +/** + * geni_se_tx_dma_prep() - Prepare the serial engine for TX DMA transfer + * @se: Pointer to the concerned serial engine. + * @buf: Pointer to the TX buffer. + * @len: Length of the TX buffer. + * @iova: Pointer to store the mapped DMA address. + * + * This function is used to prepare the buffers for DMA TX. + * + * Return: 0 on success, standard Linux error codes on failure. + */ +int geni_se_tx_dma_prep(struct geni_se *se, void *buf, size_t len, + dma_addr_t *iova) +{ + struct geni_wrapper *wrapper = se->wrapper; + u32 val; + + *iova = dma_map_single(wrapper->dev, buf, len, DMA_TO_DEVICE); + if (dma_mapping_error(wrapper->dev, *iova)) + return -EIO; + + val = GENI_SE_DMA_DONE_EN; + val |= GENI_SE_DMA_EOT_EN; + val |= GENI_SE_DMA_AHB_ERR_EN; + writel_relaxed(val, se->base + SE_DMA_TX_IRQ_EN_SET); + writel_relaxed(lower_32_bits(*iova), se->base + SE_DMA_TX_PTR_L); + writel_relaxed(upper_32_bits(*iova), se->base + SE_DMA_TX_PTR_H); + writel_relaxed(GENI_SE_DMA_EOT_BUF, se->base + SE_DMA_TX_ATTR); + writel_relaxed(len, se->base + SE_DMA_TX_LEN); + return 0; +} +EXPORT_SYMBOL(geni_se_tx_dma_prep); + +/** + * geni_se_rx_dma_prep() - Prepare the serial engine for RX DMA transfer + * @se: Pointer to the concerned serial engine. + * @buf: Pointer to the RX buffer. + * @len: Length of the RX buffer. + * @iova: Pointer to store the mapped DMA address. + * + * This function is used to prepare the buffers for DMA RX. + * + * Return: 0 on success, standard Linux error codes on failure. + */ +int geni_se_rx_dma_prep(struct geni_se *se, void *buf, size_t len, + dma_addr_t *iova) +{ + struct geni_wrapper *wrapper = se->wrapper; + u32 val; + + *iova = dma_map_single(wrapper->dev, buf, len, DMA_FROM_DEVICE); + if (dma_mapping_error(wrapper->dev, *iova)) + return -EIO; + + val = GENI_SE_DMA_DONE_EN; + val |= GENI_SE_DMA_EOT_EN; + val |= GENI_SE_DMA_AHB_ERR_EN; + writel_relaxed(val, se->base + SE_DMA_RX_IRQ_EN_SET); + writel_relaxed(lower_32_bits(*iova), se->base + SE_DMA_RX_PTR_L); + writel_relaxed(upper_32_bits(*iova), se->base + SE_DMA_RX_PTR_H); + /* RX does not have EOT buffer type bit. So just reset RX_ATTR */ + writel_relaxed(0, se->base + SE_DMA_RX_ATTR); + writel_relaxed(len, se->base + SE_DMA_RX_LEN); + return 0; +} +EXPORT_SYMBOL(geni_se_rx_dma_prep); + +/** + * geni_se_tx_dma_unprep() - Unprepare the serial engine after TX DMA transfer + * @se: Pointer to the concerned serial engine. + * @iova: DMA address of the TX buffer. + * @len: Length of the TX buffer. + * + * This function is used to unprepare the DMA buffers after DMA TX. + */ +void geni_se_tx_dma_unprep(struct geni_se *se, dma_addr_t iova, size_t len) +{ + struct geni_wrapper *wrapper = se->wrapper; + + if (iova && !dma_mapping_error(wrapper->dev, iova)) + dma_unmap_single(wrapper->dev, iova, len, DMA_TO_DEVICE); +} +EXPORT_SYMBOL(geni_se_tx_dma_unprep); + +/** + * geni_se_rx_dma_unprep() - Unprepare the serial engine after RX DMA transfer + * @se: Pointer to the concerned serial engine. + * @iova: DMA address of the RX buffer. + * @len: Length of the RX buffer. + * + * This function is used to unprepare the DMA buffers after DMA RX. + */ +void geni_se_rx_dma_unprep(struct geni_se *se, dma_addr_t iova, size_t len) +{ + struct geni_wrapper *wrapper = se->wrapper; + + if (iova && !dma_mapping_error(wrapper->dev, iova)) + dma_unmap_single(wrapper->dev, iova, len, DMA_FROM_DEVICE); +} +EXPORT_SYMBOL(geni_se_rx_dma_unprep); + +static int geni_se_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct resource *res; + struct geni_wrapper *wrapper; + int ret; + + wrapper = devm_kzalloc(dev, sizeof(*wrapper), GFP_KERNEL); + if (!wrapper) + return -ENOMEM; + + wrapper->dev = dev; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + wrapper->base = devm_ioremap_resource(dev, res); + if (IS_ERR(wrapper->base)) + return PTR_ERR(wrapper->base); + + wrapper->ahb_clks[0].id = "m-ahb"; + wrapper->ahb_clks[1].id = "s-ahb"; + ret = devm_clk_bulk_get(dev, NUM_AHB_CLKS, wrapper->ahb_clks); + if (ret) { + dev_err(dev, "Err getting AHB clks %d\n", ret); + return ret; + } + + dev_set_drvdata(dev, wrapper); + dev_dbg(dev, "GENI SE Driver probed\n"); + return devm_of_platform_populate(dev); +} + +static const struct of_device_id geni_se_dt_match[] = { + { .compatible = "qcom,geni-se-qup", }, + {} +}; +MODULE_DEVICE_TABLE(of, geni_se_dt_match); + +static struct platform_driver geni_se_driver = { + .driver = { + .name = "geni_se_qup", + .of_match_table = geni_se_dt_match, + }, + .probe = geni_se_probe, +}; +module_platform_driver(geni_se_driver); + +MODULE_DESCRIPTION("GENI Serial Engine Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/qcom/qmi_interface.c b/drivers/soc/qcom/qmi_interface.c index 321982277697..938ca41c56cd 100644 --- a/drivers/soc/qcom/qmi_interface.c +++ b/drivers/soc/qcom/qmi_interface.c @@ -639,10 +639,11 @@ int qmi_handle_init(struct qmi_handle *qmi, size_t recv_buf_size, if (ops) qmi->ops = *ops; + /* Make room for the header */ + recv_buf_size += sizeof(struct qmi_header); + /* Must also be sufficient to hold a control packet */ if (recv_buf_size < sizeof(struct qrtr_ctrl_pkt)) recv_buf_size = sizeof(struct qrtr_ctrl_pkt); - else - recv_buf_size += sizeof(struct qmi_header); qmi->recv_buf_size = recv_buf_size; qmi->recv_buf = kzalloc(recv_buf_size, GFP_KERNEL); diff --git a/drivers/soc/qcom/smd-rpm.c b/drivers/soc/qcom/smd-rpm.c index c2346752b3ea..93517ed83355 100644 --- a/drivers/soc/qcom/smd-rpm.c +++ b/drivers/soc/qcom/smd-rpm.c @@ -226,6 +226,7 @@ static const struct of_device_id qcom_smd_rpm_of_match[] = { { .compatible = "qcom,rpm-msm8916" }, { .compatible = "qcom,rpm-msm8974" }, { .compatible = "qcom,rpm-msm8996" }, + { .compatible = "qcom,rpm-msm8998" }, {} }; MODULE_DEVICE_TABLE(of, qcom_smd_rpm_of_match); diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index 0b94d62fad2b..70b2ee80d6bd 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -280,7 +280,7 @@ struct qcom_smem { struct smem_region regions[0]; }; -static struct smem_private_entry * +static void * phdr_to_last_uncached_entry(struct smem_partition_header *phdr) { void *p = phdr; @@ -288,15 +288,18 @@ phdr_to_last_uncached_entry(struct smem_partition_header *phdr) return p + le32_to_cpu(phdr->offset_free_uncached); } -static void *phdr_to_first_cached_entry(struct smem_partition_header *phdr, +static struct smem_private_entry * +phdr_to_first_cached_entry(struct smem_partition_header *phdr, size_t cacheline) { void *p = phdr; + struct smem_private_entry *e; - return p + le32_to_cpu(phdr->size) - ALIGN(sizeof(*phdr), cacheline); + return p + le32_to_cpu(phdr->size) - ALIGN(sizeof(*e), cacheline); } -static void *phdr_to_last_cached_entry(struct smem_partition_header *phdr) +static void * +phdr_to_last_cached_entry(struct smem_partition_header *phdr) { void *p = phdr; @@ -361,14 +364,14 @@ static int qcom_smem_alloc_private(struct qcom_smem *smem, end = phdr_to_last_uncached_entry(phdr); cached = phdr_to_last_cached_entry(phdr); - while (hdr < end) { - if (hdr->canary != SMEM_PRIVATE_CANARY) { - dev_err(smem->dev, - "Found invalid canary in hosts %d:%d partition\n", - phdr->host0, phdr->host1); - return -EINVAL; - } + if (smem->global_partition) { + dev_err(smem->dev, "Already found the global partition\n"); + return -EINVAL; + } + while (hdr < end) { + if (hdr->canary != SMEM_PRIVATE_CANARY) + goto bad_canary; if (le16_to_cpu(hdr->item) == item) return -EEXIST; @@ -377,7 +380,7 @@ static int qcom_smem_alloc_private(struct qcom_smem *smem, /* Check that we don't grow into the cached region */ alloc_size = sizeof(*hdr) + ALIGN(size, 8); - if ((void *)hdr + alloc_size >= cached) { + if ((void *)hdr + alloc_size > cached) { dev_err(smem->dev, "Out of memory\n"); return -ENOSPC; } @@ -397,6 +400,11 @@ static int qcom_smem_alloc_private(struct qcom_smem *smem, le32_add_cpu(&phdr->offset_free_uncached, alloc_size); return 0; +bad_canary: + dev_err(smem->dev, "Found invalid canary in hosts %hu:%hu partition\n", + le16_to_cpu(phdr->host0), le16_to_cpu(phdr->host1)); + + return -EINVAL; } static int qcom_smem_alloc_global(struct qcom_smem *smem, @@ -560,8 +568,8 @@ static void *qcom_smem_get_private(struct qcom_smem *smem, return ERR_PTR(-ENOENT); invalid_canary: - dev_err(smem->dev, "Found invalid canary in hosts %d:%d partition\n", - phdr->host0, phdr->host1); + dev_err(smem->dev, "Found invalid canary in hosts %hu:%hu partition\n", + le16_to_cpu(phdr->host0), le16_to_cpu(phdr->host1)); return ERR_PTR(-EINVAL); } @@ -647,6 +655,33 @@ int qcom_smem_get_free_space(unsigned host) } EXPORT_SYMBOL(qcom_smem_get_free_space); +/** + * qcom_smem_virt_to_phys() - return the physical address associated + * with an smem item pointer (previously returned by qcom_smem_get() + * @p: the virtual address to convert + * + * Returns 0 if the pointer provided is not within any smem region. + */ +phys_addr_t qcom_smem_virt_to_phys(void *p) +{ + unsigned i; + + for (i = 0; i < __smem->num_regions; i++) { + struct smem_region *region = &__smem->regions[i]; + + if (p < region->virt_base) + continue; + if (p < region->virt_base + region->size) { + u64 offset = p - region->virt_base; + + return (phys_addr_t)region->aux_base + offset; + } + } + + return 0; +} +EXPORT_SYMBOL(qcom_smem_virt_to_phys); + static int qcom_smem_get_sbl_version(struct qcom_smem *smem) { struct smem_header *header; @@ -695,9 +730,10 @@ static u32 qcom_smem_get_item_count(struct qcom_smem *smem) static int qcom_smem_set_global_partition(struct qcom_smem *smem) { struct smem_partition_header *header; - struct smem_ptable_entry *entry = NULL; + struct smem_ptable_entry *entry; struct smem_ptable *ptable; u32 host0, host1, size; + bool found = false; int i; ptable = qcom_smem_get_ptable(smem); @@ -709,11 +745,13 @@ static int qcom_smem_set_global_partition(struct qcom_smem *smem) host0 = le16_to_cpu(entry->host0); host1 = le16_to_cpu(entry->host1); - if (host0 == SMEM_GLOBAL_HOST && host0 == host1) + if (host0 == SMEM_GLOBAL_HOST && host0 == host1) { + found = true; break; + } } - if (!entry) { + if (!found) { dev_err(smem->dev, "Missing entry for global partition\n"); return -EINVAL; } @@ -723,11 +761,6 @@ static int qcom_smem_set_global_partition(struct qcom_smem *smem) return -EINVAL; } - if (smem->global_partition) { - dev_err(smem->dev, "Already found the global partition\n"); - return -EINVAL; - } - header = smem->regions[0].virt_base + le32_to_cpu(entry->offset); host0 = le16_to_cpu(header->host0); host1 = le16_to_cpu(header->host1); diff --git a/drivers/soc/renesas/Kconfig b/drivers/soc/renesas/Kconfig index 3bbe6114a420..1d824cbd462d 100644 --- a/drivers/soc/renesas/Kconfig +++ b/drivers/soc/renesas/Kconfig @@ -4,9 +4,11 @@ config SOC_RENESAS select SOC_BUS select RST_RCAR if ARCH_RCAR_GEN1 || ARCH_RCAR_GEN2 || \ ARCH_R8A7795 || ARCH_R8A7796 || ARCH_R8A77965 || \ - ARCH_R8A77970 || ARCH_R8A77980 || ARCH_R8A77995 + ARCH_R8A77970 || ARCH_R8A77980 || ARCH_R8A77990 || \ + ARCH_R8A77995 select SYSC_R8A7743 if ARCH_R8A7743 select SYSC_R8A7745 if ARCH_R8A7745 + select SYSC_R8A77470 if ARCH_R8A77470 select SYSC_R8A7779 if ARCH_R8A7779 select SYSC_R8A7790 if ARCH_R8A7790 select SYSC_R8A7791 if ARCH_R8A7791 || ARCH_R8A7793 @@ -17,6 +19,7 @@ config SOC_RENESAS select SYSC_R8A77965 if ARCH_R8A77965 select SYSC_R8A77970 if ARCH_R8A77970 select SYSC_R8A77980 if ARCH_R8A77980 + select SYSC_R8A77990 if ARCH_R8A77990 select SYSC_R8A77995 if ARCH_R8A77995 if SOC_RENESAS @@ -30,6 +33,10 @@ config SYSC_R8A7745 bool "RZ/G1E System Controller support" if COMPILE_TEST select SYSC_RCAR +config SYSC_R8A77470 + bool "RZ/G1C System Controller support" if COMPILE_TEST + select SYSC_RCAR + config SYSC_R8A7779 bool "R-Car H1 System Controller support" if COMPILE_TEST select SYSC_RCAR @@ -70,6 +77,10 @@ config SYSC_R8A77980 bool "R-Car V3H System Controller support" if COMPILE_TEST select SYSC_RCAR +config SYSC_R8A77990 + bool "R-Car E3 System Controller support" if COMPILE_TEST + select SYSC_RCAR + config SYSC_R8A77995 bool "R-Car D3 System Controller support" if COMPILE_TEST select SYSC_RCAR diff --git a/drivers/soc/renesas/Makefile b/drivers/soc/renesas/Makefile index ccb5ec57a262..7dc0f20d7907 100644 --- a/drivers/soc/renesas/Makefile +++ b/drivers/soc/renesas/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_SOC_RENESAS) += renesas-soc.o # SoC obj-$(CONFIG_SYSC_R8A7743) += r8a7743-sysc.o obj-$(CONFIG_SYSC_R8A7745) += r8a7745-sysc.o +obj-$(CONFIG_SYSC_R8A77470) += r8a77470-sysc.o obj-$(CONFIG_SYSC_R8A7779) += r8a7779-sysc.o obj-$(CONFIG_SYSC_R8A7790) += r8a7790-sysc.o obj-$(CONFIG_SYSC_R8A7791) += r8a7791-sysc.o @@ -15,6 +16,7 @@ obj-$(CONFIG_SYSC_R8A7796) += r8a7796-sysc.o obj-$(CONFIG_SYSC_R8A77965) += r8a77965-sysc.o obj-$(CONFIG_SYSC_R8A77970) += r8a77970-sysc.o obj-$(CONFIG_SYSC_R8A77980) += r8a77980-sysc.o +obj-$(CONFIG_SYSC_R8A77990) += r8a77990-sysc.o obj-$(CONFIG_SYSC_R8A77995) += r8a77995-sysc.o # Family diff --git a/drivers/soc/renesas/r8a77470-sysc.c b/drivers/soc/renesas/r8a77470-sysc.c new file mode 100644 index 000000000000..cfa015e208ef --- /dev/null +++ b/drivers/soc/renesas/r8a77470-sysc.c @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas RZ/G1C System Controller + * + * Copyright (C) 2018 Renesas Electronics Corp. + */ + +#include <linux/bug.h> +#include <linux/kernel.h> + +#include <dt-bindings/power/r8a77470-sysc.h> + +#include "rcar-sysc.h" + +static const struct rcar_sysc_area r8a77470_areas[] __initconst = { + { "always-on", 0, 0, R8A77470_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, + { "ca7-scu", 0x100, 0, R8A77470_PD_CA7_SCU, R8A77470_PD_ALWAYS_ON, + PD_SCU }, + { "ca7-cpu0", 0x1c0, 0, R8A77470_PD_CA7_CPU0, R8A77470_PD_CA7_SCU, + PD_CPU_NOCR }, + { "ca7-cpu1", 0x1c0, 1, R8A77470_PD_CA7_CPU1, R8A77470_PD_CA7_SCU, + PD_CPU_NOCR }, + { "sgx", 0xc0, 0, R8A77470_PD_SGX, R8A77470_PD_ALWAYS_ON }, +}; + +const struct rcar_sysc_info r8a77470_sysc_info __initconst = { + .areas = r8a77470_areas, + .num_areas = ARRAY_SIZE(r8a77470_areas), +}; diff --git a/drivers/soc/renesas/r8a77990-sysc.c b/drivers/soc/renesas/r8a77990-sysc.c new file mode 100644 index 000000000000..15579ebc5ed2 --- /dev/null +++ b/drivers/soc/renesas/r8a77990-sysc.c @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas R-Car E3 System Controller + * + * Copyright (C) 2018 Renesas Electronics Corp. + */ + +#include <linux/bug.h> +#include <linux/kernel.h> +#include <linux/sys_soc.h> + +#include <dt-bindings/power/r8a77990-sysc.h> + +#include "rcar-sysc.h" + +static struct rcar_sysc_area r8a77990_areas[] __initdata = { + { "always-on", 0, 0, R8A77990_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, + { "ca53-scu", 0x140, 0, R8A77990_PD_CA53_SCU, R8A77990_PD_ALWAYS_ON, + PD_SCU }, + { "ca53-cpu0", 0x200, 0, R8A77990_PD_CA53_CPU0, R8A77990_PD_CA53_SCU, + PD_CPU_NOCR }, + { "ca53-cpu1", 0x200, 1, R8A77990_PD_CA53_CPU1, R8A77990_PD_CA53_SCU, + PD_CPU_NOCR }, + { "cr7", 0x240, 0, R8A77990_PD_CR7, R8A77990_PD_ALWAYS_ON }, + { "a3vc", 0x380, 0, R8A77990_PD_A3VC, R8A77990_PD_ALWAYS_ON }, + { "a2vc1", 0x3c0, 1, R8A77990_PD_A2VC1, R8A77990_PD_A3VC }, + { "3dg-a", 0x100, 0, R8A77990_PD_3DG_A, R8A77990_PD_ALWAYS_ON }, + { "3dg-b", 0x100, 1, R8A77990_PD_3DG_B, R8A77990_PD_3DG_A }, +}; + +static void __init rcar_sysc_fix_parent(struct rcar_sysc_area *areas, + unsigned int num_areas, u8 id, + int new_parent) +{ + unsigned int i; + + for (i = 0; i < num_areas; i++) + if (areas[i].isr_bit == id) { + areas[i].parent = new_parent; + return; + } +} + +/* Fixups for R-Car E3 ES1.0 revision */ +static const struct soc_device_attribute r8a77990[] __initconst = { + { .soc_id = "r8a77990", .revision = "ES1.0" }, + { /* sentinel */ } +}; + +static int __init r8a77990_sysc_init(void) +{ + if (soc_device_match(r8a77990)) { + rcar_sysc_fix_parent(r8a77990_areas, + ARRAY_SIZE(r8a77990_areas), + R8A77990_PD_3DG_A, R8A77990_PD_3DG_B); + rcar_sysc_fix_parent(r8a77990_areas, + ARRAY_SIZE(r8a77990_areas), + R8A77990_PD_3DG_B, R8A77990_PD_ALWAYS_ON); + } + + return 0; +} + +const struct rcar_sysc_info r8a77990_sysc_info __initconst = { + .init = r8a77990_sysc_init, + .areas = r8a77990_areas, + .num_areas = ARRAY_SIZE(r8a77990_areas), +}; diff --git a/drivers/soc/renesas/r8a77995-sysc.c b/drivers/soc/renesas/r8a77995-sysc.c index f718429cab02..1b2ef415bbe1 100644 --- a/drivers/soc/renesas/r8a77995-sysc.c +++ b/drivers/soc/renesas/r8a77995-sysc.c @@ -10,13 +10,12 @@ #include <linux/bug.h> #include <linux/kernel.h> -#include <linux/sys_soc.h> #include <dt-bindings/power/r8a77995-sysc.h> #include "rcar-sysc.h" -static struct rcar_sysc_area r8a77995_areas[] __initdata = { +static const struct rcar_sysc_area r8a77995_areas[] __initconst = { { "always-on", 0, 0, R8A77995_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, { "ca53-scu", 0x140, 0, R8A77995_PD_CA53_SCU, R8A77995_PD_ALWAYS_ON, PD_SCU }, diff --git a/drivers/soc/renesas/rcar-rst.c b/drivers/soc/renesas/rcar-rst.c index 8e9cb7996ab0..d9c1034e70e9 100644 --- a/drivers/soc/renesas/rcar-rst.c +++ b/drivers/soc/renesas/rcar-rst.c @@ -44,6 +44,7 @@ static const struct of_device_id rcar_rst_matches[] __initconst = { /* RZ/G is handled like R-Car Gen2 */ { .compatible = "renesas,r8a7743-rst", .data = &rcar_rst_gen2 }, { .compatible = "renesas,r8a7745-rst", .data = &rcar_rst_gen2 }, + { .compatible = "renesas,r8a77470-rst", .data = &rcar_rst_gen2 }, /* R-Car Gen1 */ { .compatible = "renesas,r8a7778-reset-wdt", .data = &rcar_rst_gen1 }, { .compatible = "renesas,r8a7779-reset-wdt", .data = &rcar_rst_gen1 }, @@ -59,6 +60,7 @@ static const struct of_device_id rcar_rst_matches[] __initconst = { { .compatible = "renesas,r8a77965-rst", .data = &rcar_rst_gen3 }, { .compatible = "renesas,r8a77970-rst", .data = &rcar_rst_gen3 }, { .compatible = "renesas,r8a77980-rst", .data = &rcar_rst_gen3 }, + { .compatible = "renesas,r8a77990-rst", .data = &rcar_rst_gen3 }, { .compatible = "renesas,r8a77995-rst", .data = &rcar_rst_gen3 }, { /* sentinel */ } }; diff --git a/drivers/soc/renesas/rcar-sysc.c b/drivers/soc/renesas/rcar-sysc.c index faf20e719361..95120acc4d80 100644 --- a/drivers/soc/renesas/rcar-sysc.c +++ b/drivers/soc/renesas/rcar-sysc.c @@ -261,6 +261,9 @@ static const struct of_device_id rcar_sysc_matches[] __initconst = { #ifdef CONFIG_SYSC_R8A7745 { .compatible = "renesas,r8a7745-sysc", .data = &r8a7745_sysc_info }, #endif +#ifdef CONFIG_SYSC_R8A77470 + { .compatible = "renesas,r8a77470-sysc", .data = &r8a77470_sysc_info }, +#endif #ifdef CONFIG_SYSC_R8A7779 { .compatible = "renesas,r8a7779-sysc", .data = &r8a7779_sysc_info }, #endif @@ -293,6 +296,9 @@ static const struct of_device_id rcar_sysc_matches[] __initconst = { #ifdef CONFIG_SYSC_R8A77980 { .compatible = "renesas,r8a77980-sysc", .data = &r8a77980_sysc_info }, #endif +#ifdef CONFIG_SYSC_R8A77990 + { .compatible = "renesas,r8a77990-sysc", .data = &r8a77990_sysc_info }, +#endif #ifdef CONFIG_SYSC_R8A77995 { .compatible = "renesas,r8a77995-sysc", .data = &r8a77995_sysc_info }, #endif diff --git a/drivers/soc/renesas/rcar-sysc.h b/drivers/soc/renesas/rcar-sysc.h index dcdc9ec8eba7..a22e7cf25e30 100644 --- a/drivers/soc/renesas/rcar-sysc.h +++ b/drivers/soc/renesas/rcar-sysc.h @@ -51,6 +51,7 @@ struct rcar_sysc_info { extern const struct rcar_sysc_info r8a7743_sysc_info; extern const struct rcar_sysc_info r8a7745_sysc_info; +extern const struct rcar_sysc_info r8a77470_sysc_info; extern const struct rcar_sysc_info r8a7779_sysc_info; extern const struct rcar_sysc_info r8a7790_sysc_info; extern const struct rcar_sysc_info r8a7791_sysc_info; @@ -61,6 +62,7 @@ extern const struct rcar_sysc_info r8a7796_sysc_info; extern const struct rcar_sysc_info r8a77965_sysc_info; extern const struct rcar_sysc_info r8a77970_sysc_info; extern const struct rcar_sysc_info r8a77980_sysc_info; +extern const struct rcar_sysc_info r8a77990_sysc_info; extern const struct rcar_sysc_info r8a77995_sysc_info; diff --git a/drivers/soc/renesas/renesas-soc.c b/drivers/soc/renesas/renesas-soc.c index ea71c413c926..d44d0e687ab8 100644 --- a/drivers/soc/renesas/renesas-soc.c +++ b/drivers/soc/renesas/renesas-soc.c @@ -100,6 +100,11 @@ static const struct renesas_soc soc_rz_g1e __initconst __maybe_unused = { .id = 0x4c, }; +static const struct renesas_soc soc_rz_g1c __initconst __maybe_unused = { + .family = &fam_rzg, + .id = 0x53, +}; + static const struct renesas_soc soc_rcar_m1a __initconst __maybe_unused = { .family = &fam_rcar_gen1, }; @@ -159,6 +164,11 @@ static const struct renesas_soc soc_rcar_v3h __initconst __maybe_unused = { .id = 0x56, }; +static const struct renesas_soc soc_rcar_e3 __initconst __maybe_unused = { + .family = &fam_rcar_gen3, + .id = 0x57, +}; + static const struct renesas_soc soc_rcar_d3 __initconst __maybe_unused = { .family = &fam_rcar_gen3, .id = 0x58, @@ -192,6 +202,9 @@ static const struct of_device_id renesas_socs[] __initconst = { #ifdef CONFIG_ARCH_R8A7745 { .compatible = "renesas,r8a7745", .data = &soc_rz_g1e }, #endif +#ifdef CONFIG_ARCH_R8A77470 + { .compatible = "renesas,r8a77470", .data = &soc_rz_g1c }, +#endif #ifdef CONFIG_ARCH_R8A7778 { .compatible = "renesas,r8a7778", .data = &soc_rcar_m1a }, #endif @@ -228,6 +241,9 @@ static const struct of_device_id renesas_socs[] __initconst = { #ifdef CONFIG_ARCH_R8A77980 { .compatible = "renesas,r8a77980", .data = &soc_rcar_v3h }, #endif +#ifdef CONFIG_ARCH_R8A77990 + { .compatible = "renesas,r8a77990", .data = &soc_rcar_e3 }, +#endif #ifdef CONFIG_ARCH_R8A77995 { .compatible = "renesas,r8a77995", .data = &soc_rcar_d3 }, #endif diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c index f874baaf934c..6dff8682155f 100644 --- a/drivers/soc/rockchip/pm_domains.c +++ b/drivers/soc/rockchip/pm_domains.c @@ -19,6 +19,10 @@ #include <linux/clk.h> #include <linux/regmap.h> #include <linux/mfd/syscon.h> +#include <dt-bindings/power/px30-power.h> +#include <dt-bindings/power/rk3036-power.h> +#include <dt-bindings/power/rk3128-power.h> +#include <dt-bindings/power/rk3228-power.h> #include <dt-bindings/power/rk3288-power.h> #include <dt-bindings/power/rk3328-power.h> #include <dt-bindings/power/rk3366-power.h> @@ -104,6 +108,18 @@ struct rockchip_pmu { .active_wakeup = wakeup, \ } +#define DOMAIN_RK3036(req, ack, idle, wakeup) \ +{ \ + .req_mask = (req >= 0) ? BIT(req) : 0, \ + .req_w_mask = (req >= 0) ? BIT(req + 16) : 0, \ + .ack_mask = (ack >= 0) ? BIT(ack) : 0, \ + .idle_mask = (idle >= 0) ? BIT(idle) : 0, \ + .active_wakeup = wakeup, \ +} + +#define DOMAIN_PX30(pwr, status, req, wakeup) \ + DOMAIN_M(pwr, status, req, (req) + 16, req, wakeup) + #define DOMAIN_RK3288(pwr, status, req, wakeup) \ DOMAIN(pwr, status, req, req, (req) + 16, wakeup) @@ -256,7 +272,7 @@ static void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd, return; else if (pd->info->pwr_w_mask) regmap_write(pmu->regmap, pmu->info->pwr_offset, - on ? pd->info->pwr_mask : + on ? pd->info->pwr_w_mask : (pd->info->pwr_mask | pd->info->pwr_w_mask)); else regmap_update_bits(pmu->regmap, pmu->info->pwr_offset, @@ -700,6 +716,49 @@ err_out: return error; } +static const struct rockchip_domain_info px30_pm_domains[] = { + [PX30_PD_USB] = DOMAIN_PX30(5, 5, 10, false), + [PX30_PD_SDCARD] = DOMAIN_PX30(8, 8, 9, false), + [PX30_PD_GMAC] = DOMAIN_PX30(10, 10, 6, false), + [PX30_PD_MMC_NAND] = DOMAIN_PX30(11, 11, 5, false), + [PX30_PD_VPU] = DOMAIN_PX30(12, 12, 14, false), + [PX30_PD_VO] = DOMAIN_PX30(13, 13, 7, false), + [PX30_PD_VI] = DOMAIN_PX30(14, 14, 8, false), + [PX30_PD_GPU] = DOMAIN_PX30(15, 15, 2, false), +}; + +static const struct rockchip_domain_info rk3036_pm_domains[] = { + [RK3036_PD_MSCH] = DOMAIN_RK3036(14, 23, 30, true), + [RK3036_PD_CORE] = DOMAIN_RK3036(13, 17, 24, false), + [RK3036_PD_PERI] = DOMAIN_RK3036(12, 18, 25, false), + [RK3036_PD_VIO] = DOMAIN_RK3036(11, 19, 26, false), + [RK3036_PD_VPU] = DOMAIN_RK3036(10, 20, 27, false), + [RK3036_PD_GPU] = DOMAIN_RK3036(9, 21, 28, false), + [RK3036_PD_SYS] = DOMAIN_RK3036(8, 22, 29, false), +}; + +static const struct rockchip_domain_info rk3128_pm_domains[] = { + [RK3128_PD_CORE] = DOMAIN_RK3288(0, 0, 4, false), + [RK3128_PD_MSCH] = DOMAIN_RK3288(-1, -1, 6, true), + [RK3128_PD_VIO] = DOMAIN_RK3288(3, 3, 2, false), + [RK3128_PD_VIDEO] = DOMAIN_RK3288(2, 2, 1, false), + [RK3128_PD_GPU] = DOMAIN_RK3288(1, 1, 3, false), +}; + +static const struct rockchip_domain_info rk3228_pm_domains[] = { + [RK3228_PD_CORE] = DOMAIN_RK3036(0, 0, 16, true), + [RK3228_PD_MSCH] = DOMAIN_RK3036(1, 1, 17, true), + [RK3228_PD_BUS] = DOMAIN_RK3036(2, 2, 18, true), + [RK3228_PD_SYS] = DOMAIN_RK3036(3, 3, 19, true), + [RK3228_PD_VIO] = DOMAIN_RK3036(4, 4, 20, false), + [RK3228_PD_VOP] = DOMAIN_RK3036(5, 5, 21, false), + [RK3228_PD_VPU] = DOMAIN_RK3036(6, 6, 22, false), + [RK3228_PD_RKVDEC] = DOMAIN_RK3036(7, 7, 23, false), + [RK3228_PD_GPU] = DOMAIN_RK3036(8, 8, 24, false), + [RK3228_PD_PERI] = DOMAIN_RK3036(9, 9, 25, true), + [RK3228_PD_GMAC] = DOMAIN_RK3036(10, 10, 26, false), +}; + static const struct rockchip_domain_info rk3288_pm_domains[] = { [RK3288_PD_VIO] = DOMAIN_RK3288(7, 7, 4, false), [RK3288_PD_HEVC] = DOMAIN_RK3288(14, 10, 9, false), @@ -767,6 +826,46 @@ static const struct rockchip_domain_info rk3399_pm_domains[] = { [RK3399_PD_SDIOAUDIO] = DOMAIN_RK3399(31, 31, 29, true), }; +static const struct rockchip_pmu_info px30_pmu = { + .pwr_offset = 0x18, + .status_offset = 0x20, + .req_offset = 0x64, + .idle_offset = 0x6c, + .ack_offset = 0x6c, + + .num_domains = ARRAY_SIZE(px30_pm_domains), + .domain_info = px30_pm_domains, +}; + +static const struct rockchip_pmu_info rk3036_pmu = { + .req_offset = 0x148, + .idle_offset = 0x14c, + .ack_offset = 0x14c, + + .num_domains = ARRAY_SIZE(rk3036_pm_domains), + .domain_info = rk3036_pm_domains, +}; + +static const struct rockchip_pmu_info rk3128_pmu = { + .pwr_offset = 0x04, + .status_offset = 0x08, + .req_offset = 0x0c, + .idle_offset = 0x10, + .ack_offset = 0x10, + + .num_domains = ARRAY_SIZE(rk3128_pm_domains), + .domain_info = rk3128_pm_domains, +}; + +static const struct rockchip_pmu_info rk3228_pmu = { + .req_offset = 0x40c, + .idle_offset = 0x488, + .ack_offset = 0x488, + + .num_domains = ARRAY_SIZE(rk3228_pm_domains), + .domain_info = rk3228_pm_domains, +}; + static const struct rockchip_pmu_info rk3288_pmu = { .pwr_offset = 0x08, .status_offset = 0x0c, @@ -842,6 +941,22 @@ static const struct rockchip_pmu_info rk3399_pmu = { static const struct of_device_id rockchip_pm_domain_dt_match[] = { { + .compatible = "rockchip,px30-power-controller", + .data = (void *)&px30_pmu, + }, + { + .compatible = "rockchip,rk3036-power-controller", + .data = (void *)&rk3036_pmu, + }, + { + .compatible = "rockchip,rk3128-power-controller", + .data = (void *)&rk3128_pmu, + }, + { + .compatible = "rockchip,rk3228-power-controller", + .data = (void *)&rk3228_pmu, + }, + { .compatible = "rockchip,rk3288-power-controller", .data = (void *)&rk3288_pmu, }, diff --git a/drivers/soc/samsung/pm_domains.c b/drivers/soc/samsung/pm_domains.c index caf45cf7aa8e..ab8582971bfc 100644 --- a/drivers/soc/samsung/pm_domains.c +++ b/drivers/soc/samsung/pm_domains.c @@ -13,14 +13,11 @@ #include <linux/err.h> #include <linux/slab.h> #include <linux/pm_domain.h> -#include <linux/clk.h> #include <linux/delay.h> #include <linux/of_address.h> #include <linux/of_platform.h> #include <linux/sched.h> -#define MAX_CLK_PER_DOMAIN 4 - struct exynos_pm_domain_config { /* Value for LOCAL_PWR_CFG and STATUS fields for each domain */ u32 local_pwr_cfg; @@ -33,10 +30,6 @@ struct exynos_pm_domain { void __iomem *base; bool is_off; struct generic_pm_domain pd; - struct clk *oscclk; - struct clk *clk[MAX_CLK_PER_DOMAIN]; - struct clk *pclk[MAX_CLK_PER_DOMAIN]; - struct clk *asb_clk[MAX_CLK_PER_DOMAIN]; u32 local_pwr_cfg; }; @@ -46,29 +39,10 @@ static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on) void __iomem *base; u32 timeout, pwr; char *op; - int i; pd = container_of(domain, struct exynos_pm_domain, pd); base = pd->base; - for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) { - if (IS_ERR(pd->asb_clk[i])) - break; - clk_prepare_enable(pd->asb_clk[i]); - } - - /* Set oscclk before powering off a domain*/ - if (!power_on) { - for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) { - if (IS_ERR(pd->clk[i])) - break; - pd->pclk[i] = clk_get_parent(pd->clk[i]); - if (clk_set_parent(pd->clk[i], pd->oscclk)) - pr_err("%s: error setting oscclk as parent to clock %d\n", - domain->name, i); - } - } - pwr = power_on ? pd->local_pwr_cfg : 0; writel_relaxed(pwr, base); @@ -86,26 +60,6 @@ static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on) usleep_range(80, 100); } - /* Restore clocks after powering on a domain*/ - if (power_on) { - for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) { - if (IS_ERR(pd->clk[i])) - break; - - if (IS_ERR(pd->pclk[i])) - continue; /* Skip on first power up */ - if (clk_set_parent(pd->clk[i], pd->pclk[i])) - pr_err("%s: error setting parent to clock%d\n", - domain->name, i); - } - } - - for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) { - if (IS_ERR(pd->asb_clk[i])) - break; - clk_disable_unprepare(pd->asb_clk[i]); - } - return 0; } @@ -147,12 +101,6 @@ static __init const char *exynos_get_domain_name(struct device_node *node) return kstrdup_const(name, GFP_KERNEL); } -static const char *soc_force_no_clk[] = { - "samsung,exynos5250-clock", - "samsung,exynos5420-clock", - "samsung,exynos5800-clock", -}; - static __init int exynos4_pm_init_power_domain(void) { struct device_node *np; @@ -161,7 +109,7 @@ static __init int exynos4_pm_init_power_domain(void) for_each_matching_node_and_match(np, exynos_pm_domain_of_match, &match) { const struct exynos_pm_domain_config *pm_domain_cfg; struct exynos_pm_domain *pd; - int on, i; + int on; pm_domain_cfg = match->data; @@ -189,42 +137,6 @@ static __init int exynos4_pm_init_power_domain(void) pd->pd.power_on = exynos_pd_power_on; pd->local_pwr_cfg = pm_domain_cfg->local_pwr_cfg; - for (i = 0; i < ARRAY_SIZE(soc_force_no_clk); i++) - if (of_find_compatible_node(NULL, NULL, - soc_force_no_clk[i])) - goto no_clk; - - for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) { - char clk_name[8]; - - snprintf(clk_name, sizeof(clk_name), "asb%d", i); - pd->asb_clk[i] = of_clk_get_by_name(np, clk_name); - if (IS_ERR(pd->asb_clk[i])) - break; - } - - pd->oscclk = of_clk_get_by_name(np, "oscclk"); - if (IS_ERR(pd->oscclk)) - goto no_clk; - - for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) { - char clk_name[8]; - - snprintf(clk_name, sizeof(clk_name), "clk%d", i); - pd->clk[i] = of_clk_get_by_name(np, clk_name); - if (IS_ERR(pd->clk[i])) - break; - /* - * Skip setting parent on first power up. - * The parent at this time may not be useful at all. - */ - pd->pclk[i] = ERR_PTR(-EINVAL); - } - - if (IS_ERR(pd->clk[0])) - clk_put(pd->oscclk); - -no_clk: on = readl_relaxed(pd->base + 0x4) & pd->local_pwr_cfg; pm_genpd_init(&pd->pd, NULL, !on); diff --git a/drivers/soc/ti/knav_qmss.h b/drivers/soc/ti/knav_qmss.h index 56866ba4cfc4..3efc47e82973 100644 --- a/drivers/soc/ti/knav_qmss.h +++ b/drivers/soc/ti/knav_qmss.h @@ -19,6 +19,8 @@ #ifndef __KNAV_QMSS_H__ #define __KNAV_QMSS_H__ +#include <linux/percpu.h> + #define THRESH_GTE BIT(7) #define THRESH_LT 0 @@ -162,11 +164,11 @@ struct knav_qmgr_info { * notifies: notifier counts */ struct knav_queue_stats { - atomic_t pushes; - atomic_t pops; - atomic_t push_errors; - atomic_t pop_errors; - atomic_t notifies; + unsigned int pushes; + unsigned int pops; + unsigned int push_errors; + unsigned int pop_errors; + unsigned int notifies; }; /** @@ -283,7 +285,7 @@ struct knav_queue_inst { struct knav_queue { struct knav_reg_queue __iomem *reg_push, *reg_pop, *reg_peek; struct knav_queue_inst *inst; - struct knav_queue_stats stats; + struct knav_queue_stats __percpu *stats; knav_queue_notify_fn notifier_fn; void *notifier_fn_arg; atomic_t notifier_enabled; diff --git a/drivers/soc/ti/knav_qmss_acc.c b/drivers/soc/ti/knav_qmss_acc.c index 3d7225f4e77f..316e82e46f6c 100644 --- a/drivers/soc/ti/knav_qmss_acc.c +++ b/drivers/soc/ti/knav_qmss_acc.c @@ -405,8 +405,8 @@ static int knav_acc_init_queue(struct knav_range_info *range, { unsigned id = kq->id - range->queue_base; - kq->descs = devm_kzalloc(range->kdev->dev, - ACC_DESCS_MAX * sizeof(u32), GFP_KERNEL); + kq->descs = devm_kcalloc(range->kdev->dev, + ACC_DESCS_MAX, sizeof(u32), GFP_KERNEL); if (!kq->descs) return -ENOMEM; @@ -552,7 +552,7 @@ int knav_init_acc_range(struct knav_device *kdev, info->list_size = list_size; mem_size = PAGE_ALIGN(list_size * 2); info->mem_size = mem_size; - range->acc = devm_kzalloc(kdev->dev, channels * sizeof(*range->acc), + range->acc = devm_kcalloc(kdev->dev, channels, sizeof(*range->acc), GFP_KERNEL); if (!range->acc) return -ENOMEM; diff --git a/drivers/soc/ti/knav_qmss_queue.c b/drivers/soc/ti/knav_qmss_queue.c index 419365a8d1c2..6755f2af5619 100644 --- a/drivers/soc/ti/knav_qmss_queue.c +++ b/drivers/soc/ti/knav_qmss_queue.c @@ -99,7 +99,7 @@ void knav_queue_notify(struct knav_queue_inst *inst) continue; if (WARN_ON(!qh->notifier_fn)) continue; - atomic_inc(&qh->stats.notifies); + this_cpu_inc(qh->stats->notifies); qh->notifier_fn(qh->notifier_fn_arg); } rcu_read_unlock(); @@ -230,6 +230,12 @@ static struct knav_queue *__knav_queue_open(struct knav_queue_inst *inst, if (!qh) return ERR_PTR(-ENOMEM); + qh->stats = alloc_percpu(struct knav_queue_stats); + if (!qh->stats) { + ret = -ENOMEM; + goto err; + } + qh->flags = flags; qh->inst = inst; id = inst->id - inst->qmgr->start_queue; @@ -245,13 +251,17 @@ static struct knav_queue *__knav_queue_open(struct knav_queue_inst *inst, if (range->ops && range->ops->open_queue) ret = range->ops->open_queue(range, inst, flags); - if (ret) { - devm_kfree(inst->kdev->dev, qh); - return ERR_PTR(ret); - } + if (ret) + goto err; } list_add_tail_rcu(&qh->list, &inst->handles); return qh; + +err: + if (qh->stats) + free_percpu(qh->stats); + devm_kfree(inst->kdev->dev, qh); + return ERR_PTR(ret); } static struct knav_queue * @@ -427,6 +437,12 @@ static void knav_queue_debug_show_instance(struct seq_file *s, { struct knav_device *kdev = inst->kdev; struct knav_queue *qh; + int cpu = 0; + int pushes = 0; + int pops = 0; + int push_errors = 0; + int pop_errors = 0; + int notifies = 0; if (!knav_queue_is_busy(inst)) return; @@ -434,19 +450,22 @@ static void knav_queue_debug_show_instance(struct seq_file *s, seq_printf(s, "\tqueue id %d (%s)\n", kdev->base_id + inst->id, inst->name); for_each_handle_rcu(qh, inst) { - seq_printf(s, "\t\thandle %p: ", qh); - seq_printf(s, "pushes %8d, ", - atomic_read(&qh->stats.pushes)); - seq_printf(s, "pops %8d, ", - atomic_read(&qh->stats.pops)); - seq_printf(s, "count %8d, ", - knav_queue_get_count(qh)); - seq_printf(s, "notifies %8d, ", - atomic_read(&qh->stats.notifies)); - seq_printf(s, "push errors %8d, ", - atomic_read(&qh->stats.push_errors)); - seq_printf(s, "pop errors %8d\n", - atomic_read(&qh->stats.pop_errors)); + for_each_possible_cpu(cpu) { + pushes += per_cpu_ptr(qh->stats, cpu)->pushes; + pops += per_cpu_ptr(qh->stats, cpu)->pops; + push_errors += per_cpu_ptr(qh->stats, cpu)->push_errors; + pop_errors += per_cpu_ptr(qh->stats, cpu)->pop_errors; + notifies += per_cpu_ptr(qh->stats, cpu)->notifies; + } + + seq_printf(s, "\t\thandle %p: pushes %8d, pops %8d, count %8d, notifies %8d, push errors %8d, pop errors %8d\n", + qh, + pushes, + pops, + knav_queue_get_count(qh), + notifies, + push_errors, + pop_errors); } } @@ -563,6 +582,7 @@ void knav_queue_close(void *qhandle) if (range->ops && range->ops->close_queue) range->ops->close_queue(range, inst); } + free_percpu(qh->stats); devm_kfree(inst->kdev->dev, qh); } EXPORT_SYMBOL_GPL(knav_queue_close); @@ -636,7 +656,7 @@ int knav_queue_push(void *qhandle, dma_addr_t dma, val = (u32)dma | ((size / 16) - 1); writel_relaxed(val, &qh->reg_push[0].ptr_size_thresh); - atomic_inc(&qh->stats.pushes); + this_cpu_inc(qh->stats->pushes); return 0; } EXPORT_SYMBOL_GPL(knav_queue_push); @@ -674,7 +694,7 @@ dma_addr_t knav_queue_pop(void *qhandle, unsigned *size) if (size) *size = ((val & DESC_SIZE_MASK) + 1) * 16; - atomic_inc(&qh->stats.pops); + this_cpu_inc(qh->stats->pops); return dma; } EXPORT_SYMBOL_GPL(knav_queue_pop); diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index 60d59b003aa4..577084bb911b 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -923,9 +923,10 @@ static int davinci_spi_probe(struct platform_device *pdev) /* pdata in dspi is now updated and point pdata to that */ pdata = &dspi->pdata; - dspi->bytes_per_word = devm_kzalloc(&pdev->dev, - sizeof(*dspi->bytes_per_word) * - pdata->num_chipselect, GFP_KERNEL); + dspi->bytes_per_word = devm_kcalloc(&pdev->dev, + pdata->num_chipselect, + sizeof(*dspi->bytes_per_word), + GFP_KERNEL); if (dspi->bytes_per_word == NULL) { ret = -ENOMEM; goto free_master; diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c index e5cc07357746..f1526757aaf6 100644 --- a/drivers/spi/spi-ep93xx.c +++ b/drivers/spi/spi-ep93xx.c @@ -671,8 +671,8 @@ static int ep93xx_spi_probe(struct platform_device *pdev) master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16); master->num_chipselect = info->num_chipselect; - master->cs_gpios = devm_kzalloc(&master->dev, - sizeof(int) * master->num_chipselect, + master->cs_gpios = devm_kcalloc(&master->dev, + master->num_chipselect, sizeof(int), GFP_KERNEL); if (!master->cs_gpios) { error = -ENOMEM; diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c index b85a93cad44a..6ae92d4dca19 100644 --- a/drivers/spi/spi-gpio.c +++ b/drivers/spi/spi-gpio.c @@ -373,8 +373,9 @@ static int spi_gpio_probe(struct platform_device *pdev) spi_gpio = spi_master_get_devdata(master); - spi_gpio->cs_gpios = devm_kzalloc(&pdev->dev, - pdata->num_chipselect * sizeof(*spi_gpio->cs_gpios), + spi_gpio->cs_gpios = devm_kcalloc(&pdev->dev, + pdata->num_chipselect, + sizeof(*spi_gpio->cs_gpios), GFP_KERNEL); if (!spi_gpio->cs_gpios) return -ENOMEM; diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 866246f21041..d3b21faf6b1f 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -1511,8 +1511,9 @@ static int spi_imx_probe(struct platform_device *pdev) if (mxc_platform_info) { master->num_chipselect = mxc_platform_info->num_chipselect; if (mxc_platform_info->chipselect) { - master->cs_gpios = devm_kzalloc(&master->dev, - sizeof(int) * master->num_chipselect, GFP_KERNEL); + master->cs_gpios = devm_kcalloc(&master->dev, + master->num_chipselect, sizeof(int), + GFP_KERNEL); if (!master->cs_gpios) return -ENOMEM; diff --git a/drivers/spi/spi-oc-tiny.c b/drivers/spi/spi-oc-tiny.c index b5911282a611..085f580be7ec 100644 --- a/drivers/spi/spi-oc-tiny.c +++ b/drivers/spi/spi-oc-tiny.c @@ -213,8 +213,8 @@ static int tiny_spi_of_probe(struct platform_device *pdev) return 0; hw->gpio_cs_count = of_gpio_count(np); if (hw->gpio_cs_count > 0) { - hw->gpio_cs = devm_kzalloc(&pdev->dev, - hw->gpio_cs_count * sizeof(unsigned int), + hw->gpio_cs = devm_kcalloc(&pdev->dev, + hw->gpio_cs_count, sizeof(unsigned int), GFP_KERNEL); if (!hw->gpio_cs) return -ENOMEM; diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index 4797c57f4263..1af8c96b940e 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -2135,7 +2135,7 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id) pl022->master_info = platform_info; pl022->adev = adev; pl022->vendor = id->data; - pl022->chipselects = devm_kzalloc(dev, num_cs * sizeof(int), + pl022->chipselects = devm_kcalloc(dev, num_cs, sizeof(int), GFP_KERNEL); if (!pl022->chipselects) { status = -ENOMEM; diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index efc624f9e490..ec395a6baf9c 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -2049,7 +2049,7 @@ static int of_spi_register_master(struct spi_controller *ctlr) else if (nb < 0) return nb; - cs = devm_kzalloc(&ctlr->dev, sizeof(int) * ctlr->num_chipselect, + cs = devm_kcalloc(&ctlr->dev, ctlr->num_chipselect, sizeof(int), GFP_KERNEL); ctlr->cs_gpios = cs; diff --git a/drivers/staging/android/ion/ion_heap.c b/drivers/staging/android/ion/ion_heap.c index 772dad65396e..e8c440329708 100644 --- a/drivers/staging/android/ion/ion_heap.c +++ b/drivers/staging/android/ion/ion_heap.c @@ -25,7 +25,8 @@ void *ion_heap_map_kernel(struct ion_heap *heap, pgprot_t pgprot; struct sg_table *table = buffer->sg_table; int npages = PAGE_ALIGN(buffer->size) / PAGE_SIZE; - struct page **pages = vmalloc(sizeof(struct page *) * npages); + struct page **pages = vmalloc(array_size(npages, + sizeof(struct page *))); struct page **tmp = pages; if (!pages) diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c index 0e36b66ae5f7..731e47149af8 100644 --- a/drivers/staging/fbtft/fbtft-core.c +++ b/drivers/staging/fbtft/fbtft-core.c @@ -246,7 +246,7 @@ static int fbtft_request_gpios_dt(struct fbtft_par *par) static int fbtft_backlight_update_status(struct backlight_device *bd) { struct fbtft_par *par = bl_get_data(bd); - bool polarity = !!(bd->props.state & BL_CORE_DRIVER1); + bool polarity = par->polarity; fbtft_par_dbg(DEBUG_BACKLIGHT, par, "%s: polarity=%d, power=%d, fb_blank=%d\n", @@ -296,7 +296,7 @@ void fbtft_register_backlight(struct fbtft_par *par) /* Assume backlight is off, get polarity from current state of pin */ bl_props.power = FB_BLANK_POWERDOWN; if (!gpio_get_value(par->gpio.led[0])) - bl_props.state |= BL_CORE_DRIVER1; + par->polarity = true; bd = backlight_device_register(dev_driver_string(par->info->device), par->info->device, par, diff --git a/drivers/staging/fbtft/fbtft.h b/drivers/staging/fbtft/fbtft.h index e19e64e0d094..c7cb4a7896f4 100644 --- a/drivers/staging/fbtft/fbtft.h +++ b/drivers/staging/fbtft/fbtft.h @@ -229,6 +229,7 @@ struct fbtft_par { ktime_t update_time; bool bgr; void *extra; + bool polarity; }; #define NUMARGS(...) (sizeof((int[]){__VA_ARGS__})/sizeof(int)) diff --git a/drivers/staging/greybus/audio_topology.c b/drivers/staging/greybus/audio_topology.c index 15e57f701630..b71078339e86 100644 --- a/drivers/staging/greybus/audio_topology.c +++ b/drivers/staging/greybus/audio_topology.c @@ -144,7 +144,7 @@ static const char **gb_generate_enum_strings(struct gbaudio_module_info *gb, __u8 *data; items = le32_to_cpu(gbenum->items); - strings = devm_kzalloc(gb->dev, sizeof(char *) * items, GFP_KERNEL); + strings = devm_kcalloc(gb->dev, items, sizeof(char *), GFP_KERNEL); data = gbenum->names; for (i = 0; i < items; i++) { diff --git a/drivers/staging/greybus/camera.c b/drivers/staging/greybus/camera.c index 341f729a9779..6dded10f4155 100644 --- a/drivers/staging/greybus/camera.c +++ b/drivers/staging/greybus/camera.c @@ -1175,8 +1175,9 @@ static int gb_camera_debugfs_init(struct gb_camera *gcam) gcam->debugfs.root = debugfs_create_dir(dirname, gb_debugfs_get()); - gcam->debugfs.buffers = vmalloc(sizeof(*gcam->debugfs.buffers) * - GB_CAMERA_DEBUGFS_BUFFER_MAX); + gcam->debugfs.buffers = + vmalloc(array_size(GB_CAMERA_DEBUGFS_BUFFER_MAX, + sizeof(*gcam->debugfs.buffers))); if (!gcam->debugfs.buffers) return -ENOMEM; diff --git a/drivers/staging/media/imx/imx-media-dev.c b/drivers/staging/media/imx/imx-media-dev.c index 289d775c4820..b0be80f05767 100644 --- a/drivers/staging/media/imx/imx-media-dev.c +++ b/drivers/staging/media/imx/imx-media-dev.c @@ -303,9 +303,9 @@ static int imx_media_alloc_pad_vdev_lists(struct imx_media_dev *imxmd) list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) { entity = &sd->entity; - vdev_lists = devm_kzalloc( + vdev_lists = devm_kcalloc( imxmd->md.dev, - entity->num_pads * sizeof(*vdev_lists), + entity->num_pads, sizeof(*vdev_lists), GFP_KERNEL); if (!vdev_lists) return -ENOMEM; @@ -544,7 +544,7 @@ static int imx_media_probe(struct platform_device *pdev) goto unreg_dev; } - subdevs = devm_kzalloc(imxmd->md.dev, sizeof(*subdevs) * num_subdevs, + subdevs = devm_kcalloc(imxmd->md.dev, num_subdevs, sizeof(*subdevs), GFP_KERNEL); if (!subdevs) { ret = -ENOMEM; diff --git a/drivers/staging/media/zoran/zoran_driver.c b/drivers/staging/media/zoran/zoran_driver.c index d2e13fffbc6b..d7842224fff6 100644 --- a/drivers/staging/media/zoran/zoran_driver.c +++ b/drivers/staging/media/zoran/zoran_driver.c @@ -941,7 +941,7 @@ static int zoran_open(struct file *file) /* used to be BUZ_MAX_WIDTH/HEIGHT, but that gives overflows * on norm-change! */ fh->overlay_mask = - kmalloc(((768 + 31) / 32) * 576 * 4, GFP_KERNEL); + kmalloc(array3_size((768 + 31) / 32, 576, 4), GFP_KERNEL); if (!fh->overlay_mask) { dprintk(1, KERN_ERR @@ -1220,7 +1220,8 @@ static int setup_window(struct zoran_fh *fh, } } else if (clipcount) { /* write our own bitmap from the clips */ - vcp = vmalloc(sizeof(struct v4l2_clip) * (clipcount + 4)); + vcp = vmalloc(array_size(sizeof(struct v4l2_clip), + clipcount + 4)); if (vcp == NULL) { dprintk(1, KERN_ERR diff --git a/drivers/staging/mt7621-pinctrl/pinctrl-rt2880.c b/drivers/staging/mt7621-pinctrl/pinctrl-rt2880.c index 2d9ab2620b82..0c3e498ae99c 100644 --- a/drivers/staging/mt7621-pinctrl/pinctrl-rt2880.c +++ b/drivers/staging/mt7621-pinctrl/pinctrl-rt2880.c @@ -143,7 +143,7 @@ static int rt2880_pinctrl_dt_node_to_map(struct pinctrl_dev *pctrldev, if (!max_maps) return max_maps; - *map = kzalloc(max_maps * sizeof(struct pinctrl_map), GFP_KERNEL); + *map = kcalloc(max_maps, sizeof(struct pinctrl_map), GFP_KERNEL); if (!*map) return -ENOMEM; @@ -287,7 +287,8 @@ static int rt2880_pinmux_index(struct rt2880_priv *p) } /* allocate the group names array needed by the gpio function */ - p->group_names = devm_kzalloc(p->dev, sizeof(char *) * p->group_count, GFP_KERNEL); + p->group_names = devm_kcalloc(p->dev, p->group_count, sizeof(char *), + GFP_KERNEL); if (!p->group_names) return -1; @@ -300,8 +301,12 @@ static int rt2880_pinmux_index(struct rt2880_priv *p) p->func_count++; /* allocate our function and group mapping index buffers */ - f = p->func = devm_kzalloc(p->dev, sizeof(struct rt2880_pmx_func) * p->func_count, GFP_KERNEL); - gpio_func.groups = devm_kzalloc(p->dev, sizeof(int) * p->group_count, GFP_KERNEL); + f = p->func = devm_kcalloc(p->dev, + p->func_count, + sizeof(struct rt2880_pmx_func), + GFP_KERNEL); + gpio_func.groups = devm_kcalloc(p->dev, p->group_count, sizeof(int), + GFP_KERNEL); if (!f || !gpio_func.groups) return -1; @@ -337,7 +342,10 @@ static int rt2880_pinmux_pins(struct rt2880_priv *p) if (!p->func[i]->pin_count) continue; - p->func[i]->pins = devm_kzalloc(p->dev, sizeof(int) * p->func[i]->pin_count, GFP_KERNEL); + p->func[i]->pins = devm_kcalloc(p->dev, + p->func[i]->pin_count, + sizeof(int), + GFP_KERNEL); for (j = 0; j < p->func[i]->pin_count; j++) p->func[i]->pins[j] = p->func[i]->pin_first + j; @@ -347,11 +355,11 @@ static int rt2880_pinmux_pins(struct rt2880_priv *p) } /* the buffer that tells us which pins are gpio */ - p->gpio = devm_kzalloc(p->dev,sizeof(uint8_t) * p->max_pins, - GFP_KERNEL); + p->gpio = devm_kcalloc(p->dev,p->max_pins, sizeof(uint8_t), + GFP_KERNEL); /* the pads needed to tell pinctrl about our pins */ - p->pads = devm_kzalloc(p->dev, - sizeof(struct pinctrl_pin_desc) * p->max_pins, + p->pads = devm_kcalloc(p->dev, + p->max_pins, sizeof(struct pinctrl_pin_desc), GFP_KERNEL); if (!p->pads || !p->gpio ) { dev_err(p->dev, "Failed to allocate gpio data\n"); diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme.c b/drivers/staging/rtl8188eu/core/rtw_mlme.c index 24e92998a30c..50e7cae32f75 100644 --- a/drivers/staging/rtl8188eu/core/rtw_mlme.c +++ b/drivers/staging/rtl8188eu/core/rtw_mlme.c @@ -53,7 +53,7 @@ int rtw_init_mlme_priv(struct adapter *padapter) memset(&pmlmepriv->assoc_ssid, 0, sizeof(struct ndis_802_11_ssid)); - pbuf = vzalloc(MAX_BSS_CNT * (sizeof(struct wlan_network))); + pbuf = vzalloc(array_size(MAX_BSS_CNT, sizeof(struct wlan_network))); if (!pbuf) { res = _FAIL; diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c index 37a610d05ad2..f2cdcc2bcab4 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c @@ -597,8 +597,9 @@ static void RxReorderIndicatePacket(struct ieee80211_device *ieee, bool bMatchWinStart = false, bPktInBuf = false; IEEE80211_DEBUG(IEEE80211_DL_REORDER,"%s(): Seq is %d,pTS->RxIndicateSeq is %d, WinSize is %d\n",__func__,SeqNum,pTS->RxIndicateSeq,WinSize); - prxbIndicateArray = kmalloc(sizeof(struct ieee80211_rxb *) * - REORDER_WIN_SIZE, GFP_KERNEL); + prxbIndicateArray = kmalloc_array(REORDER_WIN_SIZE, + sizeof(struct ieee80211_rxb *), + GFP_KERNEL); if (!prxbIndicateArray) return; diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c index a4df95cc7f60..8b17400f6c13 100644 --- a/drivers/staging/rtl8192u/r8192U_core.c +++ b/drivers/staging/rtl8192u/r8192U_core.c @@ -1640,8 +1640,8 @@ static short rtl8192_usb_initendpoints(struct net_device *dev) { struct r8192_priv *priv = ieee80211_priv(dev); - priv->rx_urb = kmalloc(sizeof(struct urb *) * (MAX_RX_URB + 1), - GFP_KERNEL); + priv->rx_urb = kmalloc_array(MAX_RX_URB + 1, sizeof(struct urb *), + GFP_KERNEL); if (!priv->rx_urb) return -ENOMEM; diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme.c b/drivers/staging/rtl8723bs/core/rtw_mlme.c index cc4f115e082c..f9392b8db49b 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme.c @@ -37,7 +37,7 @@ sint _rtw_init_mlme_priv(struct adapter *padapter) memset(&pmlmepriv->assoc_ssid, 0, sizeof(struct ndis_802_11_ssid)); - pbuf = vzalloc(MAX_BSS_CNT * (sizeof(struct wlan_network))); + pbuf = vzalloc(array_size(MAX_BSS_CNT, sizeof(struct wlan_network))); if (pbuf == NULL) { res = _FAIL; diff --git a/drivers/staging/rtlwifi/efuse.c b/drivers/staging/rtlwifi/efuse.c index d7c7d146a84d..1dc71455f270 100644 --- a/drivers/staging/rtlwifi/efuse.c +++ b/drivers/staging/rtlwifi/efuse.c @@ -237,8 +237,8 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf) } /* allocate memory for efuse_tbl and efuse_word */ - efuse_tbl = kzalloc(rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE] * - sizeof(u8), GFP_ATOMIC); + efuse_tbl = kzalloc(rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE], + GFP_ATOMIC); if (!efuse_tbl) return; efuse_word = kcalloc(EFUSE_MAX_WORD_UNIT, sizeof(u16 *), GFP_ATOMIC); diff --git a/drivers/staging/rts5208/ms.c b/drivers/staging/rts5208/ms.c index 821256b95e22..b89ef15e3c20 100644 --- a/drivers/staging/rts5208/ms.c +++ b/drivers/staging/rts5208/ms.c @@ -2618,7 +2618,7 @@ static int ms_build_l2p_tbl(struct rtsx_chip *chip, int seg_no) segment = &ms_card->segment[seg_no]; if (!segment->l2p_table) { - segment->l2p_table = vmalloc(table_size * 2); + segment->l2p_table = vmalloc(array_size(table_size, 2)); if (!segment->l2p_table) { rtsx_trace(chip); goto BUILD_FAIL; diff --git a/drivers/staging/rts5208/rtsx_chip.c b/drivers/staging/rts5208/rtsx_chip.c index 4ad472dd9daf..8a823466ca2b 100644 --- a/drivers/staging/rts5208/rtsx_chip.c +++ b/drivers/staging/rts5208/rtsx_chip.c @@ -1660,13 +1660,13 @@ int rtsx_write_cfg_seq(struct rtsx_chip *chip, u8 func, u16 addr, u8 *buf, dev_dbg(rtsx_dev(chip), "dw_len = %d\n", dw_len); - data = vzalloc(dw_len * 4); + data = vzalloc(array_size(dw_len, 4)); if (!data) { rtsx_trace(chip); return STATUS_NOMEM; } - mask = vzalloc(dw_len * 4); + mask = vzalloc(array_size(dw_len, 4)); if (!mask) { vfree(data); rtsx_trace(chip); @@ -1721,7 +1721,7 @@ int rtsx_read_cfg_seq(struct rtsx_chip *chip, u8 func, u16 addr, u8 *buf, dev_dbg(rtsx_dev(chip), "dw_len = %d\n", dw_len); - data = vmalloc(dw_len * 4); + data = vmalloc(array_size(dw_len, 4)); if (!data) { rtsx_trace(chip); return STATUS_NOMEM; diff --git a/drivers/staging/unisys/visorhba/visorhba_main.c b/drivers/staging/unisys/visorhba/visorhba_main.c index 167e98f8688e..4fc521c51c0e 100644 --- a/drivers/staging/unisys/visorhba/visorhba_main.c +++ b/drivers/staging/unisys/visorhba/visorhba_main.c @@ -865,7 +865,7 @@ static void do_scsi_nolinuxstat(struct uiscmdrsp *cmdrsp, if (cmdrsp->scsi.no_disk_result == 0) return; - buf = kzalloc(sizeof(char) * 36, GFP_KERNEL); + buf = kzalloc(36, GFP_KERNEL); if (!buf) return; diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index f0e8f0f4ccb4..ee5081ba5313 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -250,10 +250,10 @@ int transport_alloc_session_tags(struct se_session *se_sess, { int rc; - se_sess->sess_cmd_map = kzalloc(tag_num * tag_size, + se_sess->sess_cmd_map = kcalloc(tag_size, tag_num, GFP_KERNEL | __GFP_NOWARN | __GFP_RETRY_MAYFAIL); if (!se_sess->sess_cmd_map) { - se_sess->sess_cmd_map = vzalloc(tag_num * tag_size); + se_sess->sess_cmd_map = vzalloc(array_size(tag_size, tag_num)); if (!se_sess->sess_cmd_map) { pr_err("Unable to allocate se_sess->sess_cmd_map\n"); return -ENOMEM; diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 94b183efd236..7f96dfa32b9c 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1717,8 +1717,9 @@ static int tcmu_configure_device(struct se_device *dev) info = &udev->uio_info; - udev->data_bitmap = kzalloc(BITS_TO_LONGS(udev->max_blocks) * - sizeof(unsigned long), GFP_KERNEL); + udev->data_bitmap = kcalloc(BITS_TO_LONGS(udev->max_blocks), + sizeof(unsigned long), + GFP_KERNEL); if (!udev->data_bitmap) { ret = -ENOMEM; goto err_bitmap_alloc; diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c index ee3a215b333a..334d98be03b9 100644 --- a/drivers/thermal/imx_thermal.c +++ b/drivers/thermal/imx_thermal.c @@ -1,11 +1,6 @@ -/* - * Copyright 2013 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 version 2 as - * published by the Free Software Foundation. - * - */ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright 2013 Freescale Semiconductor, Inc. #include <linux/clk.h> #include <linux/cpufreq.h> @@ -31,35 +26,57 @@ #define REG_CLR 0x8 #define REG_TOG 0xc -#define MISC0 0x0150 -#define MISC0_REFTOP_SELBIASOFF (1 << 3) -#define MISC1 0x0160 -#define MISC1_IRQ_TEMPHIGH (1 << 29) +/* i.MX6 specific */ +#define IMX6_MISC0 0x0150 +#define IMX6_MISC0_REFTOP_SELBIASOFF (1 << 3) +#define IMX6_MISC1 0x0160 +#define IMX6_MISC1_IRQ_TEMPHIGH (1 << 29) /* Below LOW and PANIC bits are only for TEMPMON_IMX6SX */ -#define MISC1_IRQ_TEMPLOW (1 << 28) -#define MISC1_IRQ_TEMPPANIC (1 << 27) - -#define TEMPSENSE0 0x0180 -#define TEMPSENSE0_ALARM_VALUE_SHIFT 20 -#define TEMPSENSE0_ALARM_VALUE_MASK (0xfff << TEMPSENSE0_ALARM_VALUE_SHIFT) -#define TEMPSENSE0_TEMP_CNT_SHIFT 8 -#define TEMPSENSE0_TEMP_CNT_MASK (0xfff << TEMPSENSE0_TEMP_CNT_SHIFT) -#define TEMPSENSE0_FINISHED (1 << 2) -#define TEMPSENSE0_MEASURE_TEMP (1 << 1) -#define TEMPSENSE0_POWER_DOWN (1 << 0) - -#define TEMPSENSE1 0x0190 -#define TEMPSENSE1_MEASURE_FREQ 0xffff -/* Below TEMPSENSE2 is only for TEMPMON_IMX6SX */ -#define TEMPSENSE2 0x0290 -#define TEMPSENSE2_LOW_VALUE_SHIFT 0 -#define TEMPSENSE2_LOW_VALUE_MASK 0xfff -#define TEMPSENSE2_PANIC_VALUE_SHIFT 16 -#define TEMPSENSE2_PANIC_VALUE_MASK 0xfff0000 +#define IMX6_MISC1_IRQ_TEMPLOW (1 << 28) +#define IMX6_MISC1_IRQ_TEMPPANIC (1 << 27) + +#define IMX6_TEMPSENSE0 0x0180 +#define IMX6_TEMPSENSE0_ALARM_VALUE_SHIFT 20 +#define IMX6_TEMPSENSE0_ALARM_VALUE_MASK (0xfff << 20) +#define IMX6_TEMPSENSE0_TEMP_CNT_SHIFT 8 +#define IMX6_TEMPSENSE0_TEMP_CNT_MASK (0xfff << 8) +#define IMX6_TEMPSENSE0_FINISHED (1 << 2) +#define IMX6_TEMPSENSE0_MEASURE_TEMP (1 << 1) +#define IMX6_TEMPSENSE0_POWER_DOWN (1 << 0) + +#define IMX6_TEMPSENSE1 0x0190 +#define IMX6_TEMPSENSE1_MEASURE_FREQ 0xffff +#define IMX6_TEMPSENSE1_MEASURE_FREQ_SHIFT 0 #define OCOTP_MEM0 0x0480 #define OCOTP_ANA1 0x04e0 +/* Below TEMPSENSE2 is only for TEMPMON_IMX6SX */ +#define IMX6_TEMPSENSE2 0x0290 +#define IMX6_TEMPSENSE2_LOW_VALUE_SHIFT 0 +#define IMX6_TEMPSENSE2_LOW_VALUE_MASK 0xfff +#define IMX6_TEMPSENSE2_PANIC_VALUE_SHIFT 16 +#define IMX6_TEMPSENSE2_PANIC_VALUE_MASK 0xfff0000 + +/* i.MX7 specific */ +#define IMX7_ANADIG_DIGPROG 0x800 +#define IMX7_TEMPSENSE0 0x300 +#define IMX7_TEMPSENSE0_PANIC_ALARM_SHIFT 18 +#define IMX7_TEMPSENSE0_PANIC_ALARM_MASK (0x1ff << 18) +#define IMX7_TEMPSENSE0_HIGH_ALARM_SHIFT 9 +#define IMX7_TEMPSENSE0_HIGH_ALARM_MASK (0x1ff << 9) +#define IMX7_TEMPSENSE0_LOW_ALARM_SHIFT 0 +#define IMX7_TEMPSENSE0_LOW_ALARM_MASK 0x1ff + +#define IMX7_TEMPSENSE1 0x310 +#define IMX7_TEMPSENSE1_MEASURE_FREQ_SHIFT 16 +#define IMX7_TEMPSENSE1_MEASURE_FREQ_MASK (0xffff << 16) +#define IMX7_TEMPSENSE1_FINISHED (1 << 11) +#define IMX7_TEMPSENSE1_MEASURE_TEMP (1 << 10) +#define IMX7_TEMPSENSE1_POWER_DOWN (1 << 9) +#define IMX7_TEMPSENSE1_TEMP_VALUE_SHIFT 0 +#define IMX7_TEMPSENSE1_TEMP_VALUE_MASK 0x1ff + /* The driver supports 1 passive trip point and 1 critical trip point */ enum imx_thermal_trip { IMX_TRIP_PASSIVE, @@ -72,17 +89,114 @@ enum imx_thermal_trip { #define TEMPMON_IMX6Q 1 #define TEMPMON_IMX6SX 2 +#define TEMPMON_IMX7D 3 struct thermal_soc_data { u32 version; + + u32 sensor_ctrl; + u32 power_down_mask; + u32 measure_temp_mask; + + u32 measure_freq_ctrl; + u32 measure_freq_mask; + u32 measure_freq_shift; + + u32 temp_data; + u32 temp_value_mask; + u32 temp_value_shift; + u32 temp_valid_mask; + + u32 panic_alarm_ctrl; + u32 panic_alarm_mask; + u32 panic_alarm_shift; + + u32 high_alarm_ctrl; + u32 high_alarm_mask; + u32 high_alarm_shift; + + u32 low_alarm_ctrl; + u32 low_alarm_mask; + u32 low_alarm_shift; }; static struct thermal_soc_data thermal_imx6q_data = { .version = TEMPMON_IMX6Q, + + .sensor_ctrl = IMX6_TEMPSENSE0, + .power_down_mask = IMX6_TEMPSENSE0_POWER_DOWN, + .measure_temp_mask = IMX6_TEMPSENSE0_MEASURE_TEMP, + + .measure_freq_ctrl = IMX6_TEMPSENSE1, + .measure_freq_shift = IMX6_TEMPSENSE1_MEASURE_FREQ_SHIFT, + .measure_freq_mask = IMX6_TEMPSENSE1_MEASURE_FREQ, + + .temp_data = IMX6_TEMPSENSE0, + .temp_value_mask = IMX6_TEMPSENSE0_TEMP_CNT_MASK, + .temp_value_shift = IMX6_TEMPSENSE0_TEMP_CNT_SHIFT, + .temp_valid_mask = IMX6_TEMPSENSE0_FINISHED, + + .high_alarm_ctrl = IMX6_TEMPSENSE0, + .high_alarm_mask = IMX6_TEMPSENSE0_ALARM_VALUE_MASK, + .high_alarm_shift = IMX6_TEMPSENSE0_ALARM_VALUE_SHIFT, }; static struct thermal_soc_data thermal_imx6sx_data = { .version = TEMPMON_IMX6SX, + + .sensor_ctrl = IMX6_TEMPSENSE0, + .power_down_mask = IMX6_TEMPSENSE0_POWER_DOWN, + .measure_temp_mask = IMX6_TEMPSENSE0_MEASURE_TEMP, + + .measure_freq_ctrl = IMX6_TEMPSENSE1, + .measure_freq_shift = IMX6_TEMPSENSE1_MEASURE_FREQ_SHIFT, + .measure_freq_mask = IMX6_TEMPSENSE1_MEASURE_FREQ, + + .temp_data = IMX6_TEMPSENSE0, + .temp_value_mask = IMX6_TEMPSENSE0_TEMP_CNT_MASK, + .temp_value_shift = IMX6_TEMPSENSE0_TEMP_CNT_SHIFT, + .temp_valid_mask = IMX6_TEMPSENSE0_FINISHED, + + .high_alarm_ctrl = IMX6_TEMPSENSE0, + .high_alarm_mask = IMX6_TEMPSENSE0_ALARM_VALUE_MASK, + .high_alarm_shift = IMX6_TEMPSENSE0_ALARM_VALUE_SHIFT, + + .panic_alarm_ctrl = IMX6_TEMPSENSE2, + .panic_alarm_mask = IMX6_TEMPSENSE2_PANIC_VALUE_MASK, + .panic_alarm_shift = IMX6_TEMPSENSE2_PANIC_VALUE_SHIFT, + + .low_alarm_ctrl = IMX6_TEMPSENSE2, + .low_alarm_mask = IMX6_TEMPSENSE2_LOW_VALUE_MASK, + .low_alarm_shift = IMX6_TEMPSENSE2_LOW_VALUE_SHIFT, +}; + +static struct thermal_soc_data thermal_imx7d_data = { + .version = TEMPMON_IMX7D, + + .sensor_ctrl = IMX7_TEMPSENSE1, + .power_down_mask = IMX7_TEMPSENSE1_POWER_DOWN, + .measure_temp_mask = IMX7_TEMPSENSE1_MEASURE_TEMP, + + .measure_freq_ctrl = IMX7_TEMPSENSE1, + .measure_freq_shift = IMX7_TEMPSENSE1_MEASURE_FREQ_SHIFT, + .measure_freq_mask = IMX7_TEMPSENSE1_MEASURE_FREQ_MASK, + + .temp_data = IMX7_TEMPSENSE1, + .temp_value_mask = IMX7_TEMPSENSE1_TEMP_VALUE_MASK, + .temp_value_shift = IMX7_TEMPSENSE1_TEMP_VALUE_SHIFT, + .temp_valid_mask = IMX7_TEMPSENSE1_FINISHED, + + .panic_alarm_ctrl = IMX7_TEMPSENSE1, + .panic_alarm_mask = IMX7_TEMPSENSE0_PANIC_ALARM_MASK, + .panic_alarm_shift = IMX7_TEMPSENSE0_PANIC_ALARM_SHIFT, + + .high_alarm_ctrl = IMX7_TEMPSENSE0, + .high_alarm_mask = IMX7_TEMPSENSE0_HIGH_ALARM_MASK, + .high_alarm_shift = IMX7_TEMPSENSE0_HIGH_ALARM_SHIFT, + + .low_alarm_ctrl = IMX7_TEMPSENSE0, + .low_alarm_mask = IMX7_TEMPSENSE0_LOW_ALARM_MASK, + .low_alarm_shift = IMX7_TEMPSENSE0_LOW_ALARM_SHIFT, }; struct imx_thermal_data { @@ -107,31 +221,42 @@ struct imx_thermal_data { static void imx_set_panic_temp(struct imx_thermal_data *data, int panic_temp) { + const struct thermal_soc_data *soc_data = data->socdata; struct regmap *map = data->tempmon; int critical_value; critical_value = (data->c2 - panic_temp) / data->c1; - regmap_write(map, TEMPSENSE2 + REG_CLR, TEMPSENSE2_PANIC_VALUE_MASK); - regmap_write(map, TEMPSENSE2 + REG_SET, critical_value << - TEMPSENSE2_PANIC_VALUE_SHIFT); + + regmap_write(map, soc_data->panic_alarm_ctrl + REG_CLR, + soc_data->panic_alarm_mask); + regmap_write(map, soc_data->panic_alarm_ctrl + REG_SET, + critical_value << soc_data->panic_alarm_shift); } static void imx_set_alarm_temp(struct imx_thermal_data *data, int alarm_temp) { struct regmap *map = data->tempmon; + const struct thermal_soc_data *soc_data = data->socdata; int alarm_value; data->alarm_temp = alarm_temp; - alarm_value = (data->c2 - alarm_temp) / data->c1; - regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_ALARM_VALUE_MASK); - regmap_write(map, TEMPSENSE0 + REG_SET, alarm_value << - TEMPSENSE0_ALARM_VALUE_SHIFT); + + if (data->socdata->version == TEMPMON_IMX7D) + alarm_value = alarm_temp / 1000 + data->c1 - 25; + else + alarm_value = (data->c2 - alarm_temp) / data->c1; + + regmap_write(map, soc_data->high_alarm_ctrl + REG_CLR, + soc_data->high_alarm_mask); + regmap_write(map, soc_data->high_alarm_ctrl + REG_SET, + alarm_value << soc_data->high_alarm_shift); } static int imx_get_temp(struct thermal_zone_device *tz, int *temp) { struct imx_thermal_data *data = tz->devdata; + const struct thermal_soc_data *soc_data = data->socdata; struct regmap *map = data->tempmon; unsigned int n_meas; bool wait; @@ -139,16 +264,18 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp) if (data->mode == THERMAL_DEVICE_ENABLED) { /* Check if a measurement is currently in progress */ - regmap_read(map, TEMPSENSE0, &val); - wait = !(val & TEMPSENSE0_FINISHED); + regmap_read(map, soc_data->temp_data, &val); + wait = !(val & soc_data->temp_valid_mask); } else { /* * Every time we measure the temperature, we will power on the * temperature sensor, enable measurements, take a reading, * disable measurements, power off the temperature sensor. */ - regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN); - regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP); + regmap_write(map, soc_data->sensor_ctrl + REG_CLR, + soc_data->power_down_mask); + regmap_write(map, soc_data->sensor_ctrl + REG_SET, + soc_data->measure_temp_mask); wait = true; } @@ -160,22 +287,28 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp) if (wait) usleep_range(20, 50); - regmap_read(map, TEMPSENSE0, &val); + regmap_read(map, soc_data->temp_data, &val); if (data->mode != THERMAL_DEVICE_ENABLED) { - regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_MEASURE_TEMP); - regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN); + regmap_write(map, soc_data->sensor_ctrl + REG_CLR, + soc_data->measure_temp_mask); + regmap_write(map, soc_data->sensor_ctrl + REG_SET, + soc_data->power_down_mask); } - if ((val & TEMPSENSE0_FINISHED) == 0) { + if ((val & soc_data->temp_valid_mask) == 0) { dev_dbg(&tz->device, "temp measurement never finished\n"); return -EAGAIN; } - n_meas = (val & TEMPSENSE0_TEMP_CNT_MASK) >> TEMPSENSE0_TEMP_CNT_SHIFT; + n_meas = (val & soc_data->temp_value_mask) + >> soc_data->temp_value_shift; /* See imx_init_calib() for formula derivation */ - *temp = data->c2 - n_meas * data->c1; + if (data->socdata->version == TEMPMON_IMX7D) + *temp = (n_meas - data->c1 + 25) * 1000; + else + *temp = data->c2 - n_meas * data->c1; /* Update alarm value to next higher trip point for TEMPMON_IMX6Q */ if (data->socdata->version == TEMPMON_IMX6Q) { @@ -219,21 +352,26 @@ static int imx_set_mode(struct thermal_zone_device *tz, { struct imx_thermal_data *data = tz->devdata; struct regmap *map = data->tempmon; + const struct thermal_soc_data *soc_data = data->socdata; if (mode == THERMAL_DEVICE_ENABLED) { tz->polling_delay = IMX_POLLING_DELAY; tz->passive_delay = IMX_PASSIVE_DELAY; - regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN); - regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP); + regmap_write(map, soc_data->sensor_ctrl + REG_CLR, + soc_data->power_down_mask); + regmap_write(map, soc_data->sensor_ctrl + REG_SET, + soc_data->measure_temp_mask); if (!data->irq_enabled) { data->irq_enabled = true; enable_irq(data->irq); } } else { - regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_MEASURE_TEMP); - regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN); + regmap_write(map, soc_data->sensor_ctrl + REG_CLR, + soc_data->measure_temp_mask); + regmap_write(map, soc_data->sensor_ctrl + REG_SET, + soc_data->power_down_mask); tz->polling_delay = 0; tz->passive_delay = 0; @@ -355,6 +493,15 @@ static int imx_init_calib(struct platform_device *pdev, u32 ocotp_ana1) } /* + * On i.MX7D, we only use the calibration data at 25C to get the temp, + * Tmeas = ( Nmeas - n1) + 25; n1 is the fuse value for 25C. + */ + if (data->socdata->version == TEMPMON_IMX7D) { + data->c1 = (ocotp_ana1 >> 9) & 0x1ff; + return 0; + } + + /* * The sensor is calibrated at 25 °C (aka T1) and the value measured * (aka N1) at this temperature is provided in bits [31:20] in the * i.MX's OCOTP value ANA1. @@ -492,6 +639,7 @@ static irqreturn_t imx_thermal_alarm_irq_thread(int irq, void *dev) static const struct of_device_id of_imx_thermal_match[] = { { .compatible = "fsl,imx6q-tempmon", .data = &thermal_imx6q_data, }, { .compatible = "fsl,imx6sx-tempmon", .data = &thermal_imx6sx_data, }, + { .compatible = "fsl,imx7d-tempmon", .data = &thermal_imx7d_data, }, { /* end */ } }; MODULE_DEVICE_TABLE(of, of_imx_thermal_match); @@ -523,14 +671,15 @@ static int imx_thermal_probe(struct platform_device *pdev) /* make sure the IRQ flag is clear before enabling irq on i.MX6SX */ if (data->socdata->version == TEMPMON_IMX6SX) { - regmap_write(map, MISC1 + REG_CLR, MISC1_IRQ_TEMPHIGH | - MISC1_IRQ_TEMPLOW | MISC1_IRQ_TEMPPANIC); + regmap_write(map, IMX6_MISC1 + REG_CLR, + IMX6_MISC1_IRQ_TEMPHIGH | IMX6_MISC1_IRQ_TEMPLOW + | IMX6_MISC1_IRQ_TEMPPANIC); /* * reset value of LOW ALARM is incorrect, set it to lowest * value to avoid false trigger of low alarm. */ - regmap_write(map, TEMPSENSE2 + REG_SET, - TEMPSENSE2_LOW_VALUE_MASK); + regmap_write(map, data->socdata->low_alarm_ctrl + REG_SET, + data->socdata->low_alarm_mask); } data->irq = platform_get_irq(pdev, 0); @@ -557,11 +706,17 @@ static int imx_thermal_probe(struct platform_device *pdev) } /* Make sure sensor is in known good state for measurements */ - regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN); - regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_MEASURE_TEMP); - regmap_write(map, TEMPSENSE1 + REG_CLR, TEMPSENSE1_MEASURE_FREQ); - regmap_write(map, MISC0 + REG_SET, MISC0_REFTOP_SELBIASOFF); - regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN); + regmap_write(map, data->socdata->sensor_ctrl + REG_CLR, + data->socdata->power_down_mask); + regmap_write(map, data->socdata->sensor_ctrl + REG_CLR, + data->socdata->measure_temp_mask); + regmap_write(map, data->socdata->measure_freq_ctrl + REG_CLR, + data->socdata->measure_freq_mask); + if (data->socdata->version != TEMPMON_IMX7D) + regmap_write(map, IMX6_MISC0 + REG_SET, + IMX6_MISC0_REFTOP_SELBIASOFF); + regmap_write(map, data->socdata->sensor_ctrl + REG_SET, + data->socdata->power_down_mask); data->policy = cpufreq_cpu_get(0); if (!data->policy) { @@ -626,16 +781,20 @@ static int imx_thermal_probe(struct platform_device *pdev) data->temp_passive / 1000); /* Enable measurements at ~ 10 Hz */ - regmap_write(map, TEMPSENSE1 + REG_CLR, TEMPSENSE1_MEASURE_FREQ); + regmap_write(map, data->socdata->measure_freq_ctrl + REG_CLR, + data->socdata->measure_freq_mask); measure_freq = DIV_ROUND_UP(32768, 10); /* 10 Hz */ - regmap_write(map, TEMPSENSE1 + REG_SET, measure_freq); + regmap_write(map, data->socdata->measure_freq_ctrl + REG_SET, + measure_freq << data->socdata->measure_freq_shift); imx_set_alarm_temp(data, data->temp_passive); if (data->socdata->version == TEMPMON_IMX6SX) imx_set_panic_temp(data, data->temp_critical); - regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN); - regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP); + regmap_write(map, data->socdata->sensor_ctrl + REG_CLR, + data->socdata->power_down_mask); + regmap_write(map, data->socdata->sensor_ctrl + REG_SET, + data->socdata->measure_temp_mask); data->irq_enabled = true; data->mode = THERMAL_DEVICE_ENABLED; @@ -661,7 +820,8 @@ static int imx_thermal_remove(struct platform_device *pdev) struct regmap *map = data->tempmon; /* Disable measurements */ - regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN); + regmap_write(map, data->socdata->sensor_ctrl + REG_SET, + data->socdata->power_down_mask); if (!IS_ERR(data->thermal_clk)) clk_disable_unprepare(data->thermal_clk); @@ -684,8 +844,10 @@ static int imx_thermal_suspend(struct device *dev) * temperature will be read as the thermal sensor is powered * down. */ - regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_MEASURE_TEMP); - regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN); + regmap_write(map, data->socdata->sensor_ctrl + REG_CLR, + data->socdata->measure_temp_mask); + regmap_write(map, data->socdata->sensor_ctrl + REG_SET, + data->socdata->power_down_mask); data->mode = THERMAL_DEVICE_DISABLED; clk_disable_unprepare(data->thermal_clk); @@ -702,8 +864,10 @@ static int imx_thermal_resume(struct device *dev) if (ret) return ret; /* Enabled thermal sensor after resume */ - regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN); - regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP); + regmap_write(map, data->socdata->sensor_ctrl + REG_CLR, + data->socdata->power_down_mask); + regmap_write(map, data->socdata->sensor_ctrl + REG_SET, + data->socdata->measure_temp_mask); data->mode = THERMAL_DEVICE_ENABLED; return 0; diff --git a/drivers/thermal/int340x_thermal/acpi_thermal_rel.c b/drivers/thermal/int340x_thermal/acpi_thermal_rel.c index c719167e9f28..45e7e5cbdffb 100644 --- a/drivers/thermal/int340x_thermal/acpi_thermal_rel.c +++ b/drivers/thermal/int340x_thermal/acpi_thermal_rel.c @@ -96,7 +96,7 @@ int acpi_parse_trt(acpi_handle handle, int *trt_count, struct trt **trtp, } *trt_count = p->package.count; - trts = kzalloc(*trt_count * sizeof(struct trt), GFP_KERNEL); + trts = kcalloc(*trt_count, sizeof(struct trt), GFP_KERNEL); if (!trts) { result = -ENOMEM; goto end; @@ -178,7 +178,7 @@ int acpi_parse_art(acpi_handle handle, int *art_count, struct art **artp, /* ignore p->package.elements[0], as this is _ART Revision field */ *art_count = p->package.count - 1; - arts = kzalloc(*art_count * sizeof(struct art), GFP_KERNEL); + arts = kcalloc(*art_count, sizeof(struct art), GFP_KERNEL); if (!arts) { result = -ENOMEM; goto end; diff --git a/drivers/thermal/int340x_thermal/int340x_thermal_zone.c b/drivers/thermal/int340x_thermal/int340x_thermal_zone.c index 145a5c53ff5c..9ec27ac1856b 100644 --- a/drivers/thermal/int340x_thermal/int340x_thermal_zone.c +++ b/drivers/thermal/int340x_thermal/int340x_thermal_zone.c @@ -147,9 +147,9 @@ static int int340x_thermal_get_trip_hyst(struct thermal_zone_device *zone, status = acpi_evaluate_integer(d->adev->handle, "GTSH", NULL, &hyst); if (ACPI_FAILURE(status)) - return -EIO; - - *temp = hyst * 100; + *temp = 0; + else + *temp = hyst * 100; return 0; } @@ -239,9 +239,10 @@ struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev, if (ACPI_FAILURE(status)) trip_cnt = 0; else { - int34x_thermal_zone->aux_trips = kzalloc( - sizeof(*int34x_thermal_zone->aux_trips) * - trip_cnt, GFP_KERNEL); + int34x_thermal_zone->aux_trips = + kcalloc(trip_cnt, + sizeof(*int34x_thermal_zone->aux_trips), + GFP_KERNEL); if (!int34x_thermal_zone->aux_trips) { ret = -ENOMEM; goto err_trip_alloc; diff --git a/drivers/thermal/int340x_thermal/processor_thermal_device.c b/drivers/thermal/int340x_thermal/processor_thermal_device.c index 80bbf9ce2fb6..284cf2c5a8fd 100644 --- a/drivers/thermal/int340x_thermal/processor_thermal_device.c +++ b/drivers/thermal/int340x_thermal/processor_thermal_device.c @@ -43,6 +43,9 @@ #define PCI_DEVICE_ID_PROC_BXTX_THERMAL 0x4A8C #define PCI_DEVICE_ID_PROC_BXTP_THERMAL 0x5A8C +/* GeminiLake thermal reporting device */ +#define PCI_DEVICE_ID_PROC_GLK_THERMAL 0x318C + struct power_config { u32 index; u32 min_uw; @@ -467,6 +470,7 @@ static const struct pci_device_id proc_thermal_pci_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BXTP_THERMAL)}, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_CNL_THERMAL)}, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_CFL_THERMAL)}, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_GLK_THERMAL)}, { 0, }, }; diff --git a/drivers/thermal/mtk_thermal.c b/drivers/thermal/mtk_thermal.c index c75661a3801a..0691f260f6ea 100644 --- a/drivers/thermal/mtk_thermal.c +++ b/drivers/thermal/mtk_thermal.c @@ -153,6 +153,12 @@ /* The number of sensing points per bank */ #define MT2712_NUM_SENSORS_PER_ZONE 4 +#define MT7622_TEMP_AUXADC_CHANNEL 11 +#define MT7622_NUM_SENSORS 1 +#define MT7622_NUM_ZONES 1 +#define MT7622_NUM_SENSORS_PER_ZONE 1 +#define MT7622_TS1 0 + struct mtk_thermal; struct thermal_bank_cfg { @@ -242,6 +248,12 @@ static const int mt2712_adcpnp[MT2712_NUM_SENSORS_PER_ZONE] = { static const int mt2712_mux_values[MT2712_NUM_SENSORS] = { 0, 1, 2, 3 }; +/* MT7622 thermal sensor data */ +static const int mt7622_bank_data[MT7622_NUM_SENSORS] = { MT7622_TS1, }; +static const int mt7622_msr[MT7622_NUM_SENSORS_PER_ZONE] = { TEMP_MSR0, }; +static const int mt7622_adcpnp[MT7622_NUM_SENSORS_PER_ZONE] = { TEMP_ADCPNP0, }; +static const int mt7622_mux_values[MT7622_NUM_SENSORS] = { 0, }; + /** * The MT8173 thermal controller has four banks. Each bank can read up to * four temperature sensors simultaneously. The MT8173 has a total of 5 @@ -329,6 +341,25 @@ static const struct mtk_thermal_data mt2712_thermal_data = { .sensor_mux_values = mt2712_mux_values, }; +/* + * MT7622 have only one sensing point which uses AUXADC Channel 11 for raw data + * access. + */ +static const struct mtk_thermal_data mt7622_thermal_data = { + .auxadc_channel = MT7622_TEMP_AUXADC_CHANNEL, + .num_banks = MT7622_NUM_ZONES, + .num_sensors = MT7622_NUM_SENSORS, + .bank_data = { + { + .num_sensors = 1, + .sensors = mt7622_bank_data, + }, + }, + .msr = mt7622_msr, + .adcpnp = mt7622_adcpnp, + .sensor_mux_values = mt7622_mux_values, +}; + /** * raw_to_mcelsius - convert a raw ADC value to mcelsius * @mt: The thermal controller @@ -631,6 +662,10 @@ static const struct of_device_id mtk_thermal_of_match[] = { { .compatible = "mediatek,mt2712-thermal", .data = (void *)&mt2712_thermal_data, + }, + { + .compatible = "mediatek,mt7622-thermal", + .data = (void *)&mt7622_thermal_data, }, { }, }; @@ -642,7 +677,6 @@ static int mtk_thermal_probe(struct platform_device *pdev) struct device_node *auxadc, *apmixedsys, *np = pdev->dev.of_node; struct mtk_thermal *mt; struct resource *res; - const struct of_device_id *of_id; u64 auxadc_phys_base, apmixed_phys_base; struct thermal_zone_device *tzdev; @@ -650,9 +684,7 @@ static int mtk_thermal_probe(struct platform_device *pdev) if (!mt) return -ENOMEM; - of_id = of_match_device(mtk_thermal_of_match, &pdev->dev); - if (of_id) - mt->conf = (const struct mtk_thermal_data *)of_id->data; + mt->conf = of_device_get_match_data(&pdev->dev); mt->clk_peri_therm = devm_clk_get(&pdev->dev, "therm"); if (IS_ERR(mt->clk_peri_therm)) diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c index e09f0354a4bc..977a8307fbb1 100644 --- a/drivers/thermal/of-thermal.c +++ b/drivers/thermal/of-thermal.c @@ -1,26 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * of-thermal.c - Generic Thermal Management device tree support. * * Copyright (C) 2013 Texas Instruments * Copyright (C) 2013 Eduardo Valentin <eduardo.valentin@ti.com> - * - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ #include <linux/thermal.h> #include <linux/slab.h> @@ -870,7 +853,7 @@ __init *thermal_of_build_thermal_zone(struct device_node *np) if (tz->ntrips == 0) /* must have at least one child */ goto finish; - tz->trips = kzalloc(tz->ntrips * sizeof(*tz->trips), GFP_KERNEL); + tz->trips = kcalloc(tz->ntrips, sizeof(*tz->trips), GFP_KERNEL); if (!tz->trips) { ret = -ENOMEM; goto free_tz; @@ -896,7 +879,7 @@ __init *thermal_of_build_thermal_zone(struct device_node *np) if (tz->num_tbps == 0) goto finish; - tz->tbps = kzalloc(tz->num_tbps * sizeof(*tz->tbps), GFP_KERNEL); + tz->tbps = kcalloc(tz->num_tbps, sizeof(*tz->tbps), GFP_KERNEL); if (!tz->tbps) { ret = -ENOMEM; goto free_trips; diff --git a/drivers/thermal/qcom-spmi-temp-alarm.c b/drivers/thermal/qcom-spmi-temp-alarm.c index 95f987d5aa71..ad4f3a8d6560 100644 --- a/drivers/thermal/qcom-spmi-temp-alarm.c +++ b/drivers/thermal/qcom-spmi-temp-alarm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2015, 2017, The Linux Foundation. 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 version 2 and @@ -11,6 +11,7 @@ * GNU General Public License for more details. */ +#include <linux/bitops.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/iio/consumer.h> @@ -29,13 +30,17 @@ #define QPNP_TM_REG_ALARM_CTRL 0x46 #define QPNP_TM_TYPE 0x09 -#define QPNP_TM_SUBTYPE 0x08 +#define QPNP_TM_SUBTYPE_GEN1 0x08 +#define QPNP_TM_SUBTYPE_GEN2 0x09 -#define STATUS_STAGE_MASK 0x03 +#define STATUS_GEN1_STAGE_MASK GENMASK(1, 0) +#define STATUS_GEN2_STATE_MASK GENMASK(6, 4) +#define STATUS_GEN2_STATE_SHIFT 4 -#define SHUTDOWN_CTRL1_THRESHOLD_MASK 0x03 +#define SHUTDOWN_CTRL1_OVERRIDE_MASK GENMASK(7, 6) +#define SHUTDOWN_CTRL1_THRESHOLD_MASK GENMASK(1, 0) -#define ALARM_CTRL_FORCE_ENABLE 0x80 +#define ALARM_CTRL_FORCE_ENABLE BIT(7) /* * Trip point values based on threshold control @@ -58,6 +63,7 @@ struct qpnp_tm_chip { struct regmap *map; struct thermal_zone_device *tz_dev; + unsigned int subtype; long temp; unsigned int thresh; unsigned int stage; @@ -66,6 +72,9 @@ struct qpnp_tm_chip { struct iio_channel *adc; }; +/* This array maps from GEN2 alarm state to GEN1 alarm stage */ +static const unsigned int alarm_state_map[8] = {0, 1, 1, 2, 2, 3, 3, 3}; + static int qpnp_tm_read(struct qpnp_tm_chip *chip, u16 addr, u8 *data) { unsigned int val; @@ -84,30 +93,59 @@ static int qpnp_tm_write(struct qpnp_tm_chip *chip, u16 addr, u8 data) return regmap_write(chip->map, chip->base + addr, data); } +/** + * qpnp_tm_get_temp_stage() - return over-temperature stage + * @chip: Pointer to the qpnp_tm chip + * + * Return: stage (GEN1) or state (GEN2) on success, or errno on failure. + */ +static int qpnp_tm_get_temp_stage(struct qpnp_tm_chip *chip) +{ + int ret; + u8 reg = 0; + + ret = qpnp_tm_read(chip, QPNP_TM_REG_STATUS, ®); + if (ret < 0) + return ret; + + if (chip->subtype == QPNP_TM_SUBTYPE_GEN1) + ret = reg & STATUS_GEN1_STAGE_MASK; + else + ret = (reg & STATUS_GEN2_STATE_MASK) >> STATUS_GEN2_STATE_SHIFT; + + return ret; +} + /* * This function updates the internal temp value based on the * current thermal stage and threshold as well as the previous stage */ static int qpnp_tm_update_temp_no_adc(struct qpnp_tm_chip *chip) { - unsigned int stage; + unsigned int stage, stage_new, stage_old; int ret; - u8 reg = 0; - ret = qpnp_tm_read(chip, QPNP_TM_REG_STATUS, ®); + ret = qpnp_tm_get_temp_stage(chip); if (ret < 0) return ret; + stage = ret; - stage = reg & STATUS_STAGE_MASK; + if (chip->subtype == QPNP_TM_SUBTYPE_GEN1) { + stage_new = stage; + stage_old = chip->stage; + } else { + stage_new = alarm_state_map[stage]; + stage_old = alarm_state_map[chip->stage]; + } - if (stage > chip->stage) { + if (stage_new > stage_old) { /* increasing stage, use lower bound */ - chip->temp = (stage - 1) * TEMP_STAGE_STEP + + chip->temp = (stage_new - 1) * TEMP_STAGE_STEP + chip->thresh * TEMP_THRESH_STEP + TEMP_STAGE_HYSTERESIS + TEMP_THRESH_MIN; - } else if (stage < chip->stage) { + } else if (stage_new < stage_old) { /* decreasing stage, use upper bound */ - chip->temp = stage * TEMP_STAGE_STEP + + chip->temp = stage_new * TEMP_STAGE_STEP + chip->thresh * TEMP_THRESH_STEP - TEMP_STAGE_HYSTERESIS + TEMP_THRESH_MIN; } @@ -162,28 +200,37 @@ static irqreturn_t qpnp_tm_isr(int irq, void *data) */ static int qpnp_tm_init(struct qpnp_tm_chip *chip) { + unsigned int stage; int ret; - u8 reg; + u8 reg = 0; - chip->thresh = THRESH_MIN; + ret = qpnp_tm_read(chip, QPNP_TM_REG_SHUTDOWN_CTRL1, ®); + if (ret < 0) + return ret; + + chip->thresh = reg & SHUTDOWN_CTRL1_THRESHOLD_MASK; chip->temp = DEFAULT_TEMP; - ret = qpnp_tm_read(chip, QPNP_TM_REG_STATUS, ®); + ret = qpnp_tm_get_temp_stage(chip); if (ret < 0) return ret; + chip->stage = ret; - chip->stage = reg & STATUS_STAGE_MASK; + stage = chip->subtype == QPNP_TM_SUBTYPE_GEN1 + ? chip->stage : alarm_state_map[chip->stage]; - if (chip->stage) + if (stage) chip->temp = chip->thresh * TEMP_THRESH_STEP + - (chip->stage - 1) * TEMP_STAGE_STEP + + (stage - 1) * TEMP_STAGE_STEP + TEMP_THRESH_MIN; /* * Set threshold and disable software override of stage 2 and 3 * shutdowns. */ - reg = chip->thresh & SHUTDOWN_CTRL1_THRESHOLD_MASK; + chip->thresh = THRESH_MIN; + reg &= ~(SHUTDOWN_CTRL1_OVERRIDE_MASK | SHUTDOWN_CTRL1_THRESHOLD_MASK); + reg |= chip->thresh & SHUTDOWN_CTRL1_THRESHOLD_MASK; ret = qpnp_tm_write(chip, QPNP_TM_REG_SHUTDOWN_CTRL1, reg); if (ret < 0) return ret; @@ -246,12 +293,15 @@ static int qpnp_tm_probe(struct platform_device *pdev) return ret; } - if (type != QPNP_TM_TYPE || subtype != QPNP_TM_SUBTYPE) { + if (type != QPNP_TM_TYPE || (subtype != QPNP_TM_SUBTYPE_GEN1 + && subtype != QPNP_TM_SUBTYPE_GEN2)) { dev_err(&pdev->dev, "invalid type 0x%02x or subtype 0x%02x\n", type, subtype); return -ENODEV; } + chip->subtype = subtype; + ret = qpnp_tm_init(chip); if (ret < 0) { dev_err(&pdev->dev, "init failed\n"); diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c index c2c34425279d..3440166c2ae9 100644 --- a/drivers/thermal/qcom/tsens.c +++ b/drivers/thermal/qcom/tsens.c @@ -115,6 +115,7 @@ static int tsens_probe(struct platform_device *pdev) struct tsens_device *tmdev; const struct tsens_data *data; const struct of_device_id *id; + u32 num_sensors; if (pdev->dev.of_node) dev = &pdev->dev; @@ -129,19 +130,24 @@ static int tsens_probe(struct platform_device *pdev) else data = &data_8960; - if (data->num_sensors <= 0) { + num_sensors = data->num_sensors; + + if (np) + of_property_read_u32(np, "#qcom,sensors", &num_sensors); + + if (num_sensors <= 0) { dev_err(dev, "invalid number of sensors\n"); return -EINVAL; } tmdev = devm_kzalloc(dev, - struct_size(tmdev, sensor, data->num_sensors), + struct_size(tmdev, sensor, num_sensors), GFP_KERNEL); if (!tmdev) return -ENOMEM; tmdev->dev = dev; - tmdev->num_sensors = data->num_sensors; + tmdev->num_sensors = num_sensors; tmdev->ops = data->ops; for (i = 0; i < tmdev->num_sensors; i++) { if (data->hw_ids) diff --git a/drivers/thermal/rcar_gen3_thermal.c b/drivers/thermal/rcar_gen3_thermal.c index 561a0a332208..766521eb7071 100644 --- a/drivers/thermal/rcar_gen3_thermal.c +++ b/drivers/thermal/rcar_gen3_thermal.c @@ -132,7 +132,7 @@ static inline void rcar_gen3_thermal_write(struct rcar_gen3_thermal_tsc *tsc, #define RCAR3_THERMAL_GRAN 500 /* mili Celsius */ /* no idea where these constants come from */ -#define TJ_1 96 +#define TJ_1 116 #define TJ_3 -41 static void rcar_gen3_thermal_calc_coefs(struct equation_coefs *coef, @@ -146,7 +146,7 @@ static void rcar_gen3_thermal_calc_coefs(struct equation_coefs *coef, * Division is not scaled in BSP and if scaled it might overflow * the dividend (4095 * 4095 << 14 > INT_MAX) so keep it unscaled */ - tj_2 = (FIXPT_INT((ptat[1] - ptat[2]) * 137) + tj_2 = (FIXPT_INT((ptat[1] - ptat[2]) * 157) / (ptat[0] - ptat[2])) - FIXPT_INT(41); coef->a1 = FIXPT_DIV(FIXPT_INT(thcode[1] - thcode[2]), @@ -207,8 +207,8 @@ static int rcar_gen3_thermal_set_trips(void *devdata, int low, int high) { struct rcar_gen3_thermal_tsc *tsc = devdata; - low = clamp_val(low, -40000, 125000); - high = clamp_val(high, -40000, 125000); + low = clamp_val(low, -40000, 120000); + high = clamp_val(high, -40000, 120000); rcar_gen3_thermal_write(tsc, REG_GEN3_IRQTEMP1, rcar_gen3_thermal_mcelsius_to_temp(tsc, low)); @@ -329,6 +329,7 @@ static void rcar_gen3_thermal_init(struct rcar_gen3_thermal_tsc *tsc) static const struct of_device_id rcar_gen3_thermal_dt_ids[] = { { .compatible = "renesas,r8a7795-thermal", }, { .compatible = "renesas,r8a7796-thermal", }, + { .compatible = "renesas,r8a77965-thermal", }, {}, }; MODULE_DEVICE_TABLE(of, rcar_gen3_thermal_dt_ids); @@ -354,11 +355,11 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) /* default values if FUSEs are missing */ /* TODO: Read values from hardware on supported platforms */ - int ptat[3] = { 2351, 1509, 435 }; + int ptat[3] = { 2631, 1509, 435 }; int thcode[TSC_MAX_NUM][3] = { - { 3248, 2800, 2221 }, - { 3245, 2795, 2216 }, - { 3250, 2805, 2237 }, + { 3397, 2800, 2221 }, + { 3393, 2795, 2216 }, + { 3389, 2805, 2237 }, }; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); diff --git a/drivers/thermal/rcar_thermal.c b/drivers/thermal/rcar_thermal.c index 73e5fee6cf1d..45fb284d4c11 100644 --- a/drivers/thermal/rcar_thermal.c +++ b/drivers/thermal/rcar_thermal.c @@ -58,10 +58,47 @@ struct rcar_thermal_common { spinlock_t lock; }; +struct rcar_thermal_chip { + unsigned int use_of_thermal : 1; + unsigned int has_filonoff : 1; + unsigned int irq_per_ch : 1; + unsigned int needs_suspend_resume : 1; + unsigned int nirqs; +}; + +static const struct rcar_thermal_chip rcar_thermal = { + .use_of_thermal = 0, + .has_filonoff = 1, + .irq_per_ch = 0, + .needs_suspend_resume = 0, + .nirqs = 1, +}; + +static const struct rcar_thermal_chip rcar_gen2_thermal = { + .use_of_thermal = 1, + .has_filonoff = 1, + .irq_per_ch = 0, + .needs_suspend_resume = 0, + .nirqs = 1, +}; + +static const struct rcar_thermal_chip rcar_gen3_thermal = { + .use_of_thermal = 1, + .has_filonoff = 0, + .irq_per_ch = 1, + .needs_suspend_resume = 1, + /* + * The Gen3 chip has 3 interrupts, but this driver uses only 2 + * interrupts to detect a temperature change, rise or fall. + */ + .nirqs = 2, +}; + struct rcar_thermal_priv { void __iomem *base; struct rcar_thermal_common *common; struct thermal_zone_device *zone; + const struct rcar_thermal_chip *chip; struct delayed_work work; struct mutex lock; struct list_head list; @@ -77,13 +114,20 @@ struct rcar_thermal_priv { #define rcar_priv_to_dev(priv) ((priv)->common->dev) #define rcar_has_irq_support(priv) ((priv)->common->base) #define rcar_id_to_shift(priv) ((priv)->id * 8) -#define rcar_of_data(dev) ((unsigned long)of_device_get_match_data(dev)) -#define rcar_use_of_thermal(dev) (rcar_of_data(dev) == USE_OF_THERMAL) -#define USE_OF_THERMAL 1 static const struct of_device_id rcar_thermal_dt_ids[] = { - { .compatible = "renesas,rcar-thermal", }, - { .compatible = "renesas,rcar-gen2-thermal", .data = (void *)USE_OF_THERMAL }, + { + .compatible = "renesas,rcar-thermal", + .data = &rcar_thermal, + }, + { + .compatible = "renesas,rcar-gen2-thermal", + .data = &rcar_gen2_thermal, + }, + { + .compatible = "renesas,thermal-r8a77995", + .data = &rcar_gen3_thermal, + }, {}, }; MODULE_DEVICE_TABLE(of, rcar_thermal_dt_ids); @@ -190,7 +234,8 @@ static int rcar_thermal_update_temp(struct rcar_thermal_priv *priv) * enable IRQ */ if (rcar_has_irq_support(priv)) { - rcar_thermal_write(priv, FILONOFF, 0); + if (priv->chip->has_filonoff) + rcar_thermal_write(priv, FILONOFF, 0); /* enable Rising/Falling edge interrupt */ rcar_thermal_write(priv, POSNEG, 0x1); @@ -420,7 +465,7 @@ static int rcar_thermal_remove(struct platform_device *pdev) rcar_thermal_for_each_priv(priv, common) { rcar_thermal_irq_disable(priv); - if (rcar_use_of_thermal(dev)) + if (priv->chip->use_of_thermal) thermal_remove_hwmon_sysfs(priv->zone); else thermal_zone_device_unregister(priv->zone); @@ -438,6 +483,7 @@ static int rcar_thermal_probe(struct platform_device *pdev) struct rcar_thermal_priv *priv; struct device *dev = &pdev->dev; struct resource *res, *irq; + const struct rcar_thermal_chip *chip = of_device_get_match_data(dev); int mres = 0; int i; int ret = -ENODEV; @@ -457,19 +503,35 @@ static int rcar_thermal_probe(struct platform_device *pdev) pm_runtime_enable(dev); pm_runtime_get_sync(dev); - irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (irq) { - /* - * platform has IRQ support. - * Then, driver uses common registers - * rcar_has_irq_support() will be enabled - */ - res = platform_get_resource(pdev, IORESOURCE_MEM, mres++); - common->base = devm_ioremap_resource(dev, res); - if (IS_ERR(common->base)) - return PTR_ERR(common->base); + for (i = 0; i < chip->nirqs; i++) { + irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!irq) + continue; + if (!common->base) { + /* + * platform has IRQ support. + * Then, driver uses common registers + * rcar_has_irq_support() will be enabled + */ + res = platform_get_resource(pdev, IORESOURCE_MEM, + mres++); + common->base = devm_ioremap_resource(dev, res); + if (IS_ERR(common->base)) + return PTR_ERR(common->base); + + idle = 0; /* polling delay is not needed */ + } - idle = 0; /* polling delay is not needed */ + ret = devm_request_irq(dev, irq->start, rcar_thermal_irq, + IRQF_SHARED, dev_name(dev), common); + if (ret) { + dev_err(dev, "irq request failed\n "); + goto error_unregister; + } + + /* update ENR bits */ + if (chip->irq_per_ch) + enr_bits |= 1 << i; } for (i = 0;; i++) { @@ -491,6 +553,7 @@ static int rcar_thermal_probe(struct platform_device *pdev) priv->common = common; priv->id = i; + priv->chip = chip; mutex_init(&priv->lock); INIT_LIST_HEAD(&priv->list); INIT_DELAYED_WORK(&priv->work, rcar_thermal_work); @@ -498,7 +561,7 @@ static int rcar_thermal_probe(struct platform_device *pdev) if (ret < 0) goto error_unregister; - if (rcar_use_of_thermal(dev)) + if (chip->use_of_thermal) priv->zone = devm_thermal_zone_of_sensor_register( dev, i, priv, &rcar_thermal_zone_of_ops); @@ -515,7 +578,7 @@ static int rcar_thermal_probe(struct platform_device *pdev) goto error_unregister; } - if (rcar_use_of_thermal(dev)) { + if (chip->use_of_thermal) { /* * thermal_zone doesn't enable hwmon as default, * but, enable it here to keep compatible @@ -531,20 +594,12 @@ static int rcar_thermal_probe(struct platform_device *pdev) list_move_tail(&priv->list, &common->head); /* update ENR bits */ - enr_bits |= 3 << (i * 8); + if (!chip->irq_per_ch) + enr_bits |= 3 << (i * 8); } - /* enable temperature comparation */ - if (irq) { - ret = devm_request_irq(dev, irq->start, rcar_thermal_irq, 0, - dev_name(dev), common); - if (ret) { - dev_err(dev, "irq request failed\n "); - goto error_unregister; - } - + if (enr_bits) rcar_thermal_common_write(common, ENR, enr_bits); - } dev_info(dev, "%d sensor probed\n", i); @@ -556,9 +611,48 @@ error_unregister: return ret; } +#ifdef CONFIG_PM_SLEEP +static int rcar_thermal_suspend(struct device *dev) +{ + struct rcar_thermal_common *common = dev_get_drvdata(dev); + struct rcar_thermal_priv *priv = list_first_entry(&common->head, + typeof(*priv), list); + + if (priv->chip->needs_suspend_resume) { + rcar_thermal_common_write(common, ENR, 0); + rcar_thermal_irq_disable(priv); + rcar_thermal_bset(priv, THSCR, CPCTL, 0); + } + + return 0; +} + +static int rcar_thermal_resume(struct device *dev) +{ + struct rcar_thermal_common *common = dev_get_drvdata(dev); + struct rcar_thermal_priv *priv = list_first_entry(&common->head, + typeof(*priv), list); + int ret; + + if (priv->chip->needs_suspend_resume) { + ret = rcar_thermal_update_temp(priv); + if (ret < 0) + return ret; + rcar_thermal_irq_enable(priv); + rcar_thermal_common_write(common, ENR, 0x03); + } + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(rcar_thermal_pm_ops, rcar_thermal_suspend, + rcar_thermal_resume); + static struct platform_driver rcar_thermal_driver = { .driver = { .name = "rcar_thermal", + .pm = &rcar_thermal_pm_ops, .of_match_table = rcar_thermal_dt_ids, }, .probe = rcar_thermal_probe, diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c index ac83f721db24..a992e51ef065 100644 --- a/drivers/thermal/samsung/exynos_tmu.c +++ b/drivers/thermal/samsung/exynos_tmu.c @@ -29,13 +29,14 @@ #include <linux/io.h> #include <linux/interrupt.h> #include <linux/module.h> -#include <linux/of.h> +#include <linux/of_device.h> #include <linux/of_address.h> #include <linux/of_irq.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> -#include "exynos_tmu.h" +#include <dt-bindings/thermal/thermal_exynos.h> + #include "../thermal_core.h" /* Exynos generic registers */ @@ -75,9 +76,6 @@ #define EXYNOS_TMU_THERM_TRIP_EN_SHIFT 12 #define EXYNOS_TMU_INTEN_RISE0_SHIFT 0 -#define EXYNOS_TMU_INTEN_RISE1_SHIFT 4 -#define EXYNOS_TMU_INTEN_RISE2_SHIFT 8 -#define EXYNOS_TMU_INTEN_RISE3_SHIFT 12 #define EXYNOS_TMU_INTEN_FALL0_SHIFT 16 #define EXYNOS_EMUL_TIME 0x57F0 @@ -98,11 +96,6 @@ #define EXYNOS4412_MUX_ADDR_SHIFT 20 /* Exynos5433 specific registers */ -#define EXYNOS5433_TMU_REG_CONTROL1 0x024 -#define EXYNOS5433_TMU_SAMPLING_INTERVAL 0x02c -#define EXYNOS5433_TMU_COUNTER_VALUE0 0x030 -#define EXYNOS5433_TMU_COUNTER_VALUE1 0x034 -#define EXYNOS5433_TMU_REG_CURRENT_TEMP1 0x044 #define EXYNOS5433_THD_TEMP_RISE3_0 0x050 #define EXYNOS5433_THD_TEMP_RISE7_4 0x054 #define EXYNOS5433_THD_TEMP_FALL3_0 0x060 @@ -123,27 +116,7 @@ #define EXYNOS5433_PD_DET_EN 1 -/*exynos5440 specific registers*/ -#define EXYNOS5440_TMU_S0_7_TRIM 0x000 -#define EXYNOS5440_TMU_S0_7_CTRL 0x020 -#define EXYNOS5440_TMU_S0_7_DEBUG 0x040 -#define EXYNOS5440_TMU_S0_7_TEMP 0x0f0 -#define EXYNOS5440_TMU_S0_7_TH0 0x110 -#define EXYNOS5440_TMU_S0_7_TH1 0x130 -#define EXYNOS5440_TMU_S0_7_TH2 0x150 -#define EXYNOS5440_TMU_S0_7_IRQEN 0x210 -#define EXYNOS5440_TMU_S0_7_IRQ 0x230 -/* exynos5440 common registers */ -#define EXYNOS5440_TMU_IRQ_STATUS 0x000 -#define EXYNOS5440_TMU_PMIN 0x004 - -#define EXYNOS5440_TMU_INTEN_RISE0_SHIFT 0 -#define EXYNOS5440_TMU_INTEN_RISE1_SHIFT 1 -#define EXYNOS5440_TMU_INTEN_RISE2_SHIFT 2 -#define EXYNOS5440_TMU_INTEN_RISE3_SHIFT 3 -#define EXYNOS5440_TMU_INTEN_FALL0_SHIFT 4 -#define EXYNOS5440_TMU_TH_RISE4_SHIFT 24 -#define EXYNOS5440_EFUSE_SWAP_OFFSET 8 +#define EXYNOS5433_G3D_BASE 0x10070000 /* Exynos7 specific registers */ #define EXYNOS7_THD_TEMP_RISE7_6 0x50 @@ -155,22 +128,32 @@ #define EXYNOS7_TMU_TEMP_MASK 0x1ff #define EXYNOS7_PD_DET_EN_SHIFT 23 #define EXYNOS7_TMU_INTEN_RISE0_SHIFT 0 -#define EXYNOS7_TMU_INTEN_RISE1_SHIFT 1 -#define EXYNOS7_TMU_INTEN_RISE2_SHIFT 2 -#define EXYNOS7_TMU_INTEN_RISE3_SHIFT 3 -#define EXYNOS7_TMU_INTEN_RISE4_SHIFT 4 -#define EXYNOS7_TMU_INTEN_RISE5_SHIFT 5 -#define EXYNOS7_TMU_INTEN_RISE6_SHIFT 6 -#define EXYNOS7_TMU_INTEN_RISE7_SHIFT 7 #define EXYNOS7_EMUL_DATA_SHIFT 7 #define EXYNOS7_EMUL_DATA_MASK 0x1ff +#define EXYNOS_FIRST_POINT_TRIM 25 +#define EXYNOS_SECOND_POINT_TRIM 85 + +#define EXYNOS_NOISE_CANCEL_MODE 4 + #define MCELSIUS 1000 + +enum soc_type { + SOC_ARCH_EXYNOS3250 = 1, + SOC_ARCH_EXYNOS4210, + SOC_ARCH_EXYNOS4412, + SOC_ARCH_EXYNOS5250, + SOC_ARCH_EXYNOS5260, + SOC_ARCH_EXYNOS5420, + SOC_ARCH_EXYNOS5420_TRIMINFO, + SOC_ARCH_EXYNOS5433, + SOC_ARCH_EXYNOS7, +}; + /** * struct exynos_tmu_data : A structure to hold the private data of the TMU driver * @id: identifier of the one instance of the TMU controller. - * @pdata: pointer to the tmu platform/configuration data * @base: base address of the single instance of the TMU controller. * @base_second: base address of the common registers of the TMU controller. * @irq: irq number of the TMU controller. @@ -180,8 +163,17 @@ * @clk: pointer to the clock structure. * @clk_sec: pointer to the clock structure for accessing the base_second. * @sclk: pointer to the clock structure for accessing the tmu special clk. + * @cal_type: calibration type for temperature + * @efuse_value: SoC defined fuse value + * @min_efuse_value: minimum valid trimming data + * @max_efuse_value: maximum valid trimming data * @temp_error1: fused value of the first point trim. * @temp_error2: fused value of the second point trim. + * @gain: gain of amplifier in the positive-TC generator block + * 0 < gain <= 15 + * @reference_voltage: reference voltage of amplifier + * in the positive-TC generator block + * 0 < reference_voltage <= 31 * @regulator: pointer to the TMU regulator structure. * @reg_conf: pointer to structure to register with core thermal. * @ntrip: number of supported trip points. @@ -194,7 +186,6 @@ */ struct exynos_tmu_data { int id; - struct exynos_tmu_platform_data *pdata; void __iomem *base; void __iomem *base_second; int irq; @@ -202,71 +193,42 @@ struct exynos_tmu_data { struct work_struct irq_work; struct mutex lock; struct clk *clk, *clk_sec, *sclk; + u32 cal_type; + u32 efuse_value; + u32 min_efuse_value; + u32 max_efuse_value; u16 temp_error1, temp_error2; + u8 gain; + u8 reference_voltage; struct regulator *regulator; struct thermal_zone_device *tzd; unsigned int ntrip; bool enabled; - int (*tmu_initialize)(struct platform_device *pdev); + void (*tmu_set_trip_temp)(struct exynos_tmu_data *data, int trip, + u8 temp); + void (*tmu_set_trip_hyst)(struct exynos_tmu_data *data, int trip, + u8 temp, u8 hyst); + void (*tmu_initialize)(struct platform_device *pdev); void (*tmu_control)(struct platform_device *pdev, bool on); int (*tmu_read)(struct exynos_tmu_data *data); void (*tmu_set_emulation)(struct exynos_tmu_data *data, int temp); void (*tmu_clear_irqs)(struct exynos_tmu_data *data); }; -static void exynos_report_trigger(struct exynos_tmu_data *p) -{ - char data[10], *envp[] = { data, NULL }; - struct thermal_zone_device *tz = p->tzd; - int temp; - unsigned int i; - - if (!tz) { - pr_err("No thermal zone device defined\n"); - return; - } - - thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); - - mutex_lock(&tz->lock); - /* Find the level for which trip happened */ - for (i = 0; i < of_thermal_get_ntrips(tz); i++) { - tz->ops->get_trip_temp(tz, i, &temp); - if (tz->last_temperature < temp) - break; - } - - snprintf(data, sizeof(data), "%u", i); - kobject_uevent_env(&tz->device.kobj, KOBJ_CHANGE, envp); - mutex_unlock(&tz->lock); -} - /* * TMU treats temperature as a mapped temperature code. * The temperature is converted differently depending on the calibration type. */ static int temp_to_code(struct exynos_tmu_data *data, u8 temp) { - struct exynos_tmu_platform_data *pdata = data->pdata; - int temp_code; - - switch (pdata->cal_type) { - case TYPE_TWO_POINT_TRIMMING: - temp_code = (temp - pdata->first_point_trim) * - (data->temp_error2 - data->temp_error1) / - (pdata->second_point_trim - pdata->first_point_trim) + - data->temp_error1; - break; - case TYPE_ONE_POINT_TRIMMING: - temp_code = temp + data->temp_error1 - pdata->first_point_trim; - break; - default: - temp_code = temp + pdata->default_temp_offset; - break; - } + if (data->cal_type == TYPE_ONE_POINT_TRIMMING) + return temp + data->temp_error1 - EXYNOS_FIRST_POINT_TRIM; - return temp_code; + return (temp - EXYNOS_FIRST_POINT_TRIM) * + (data->temp_error2 - data->temp_error1) / + (EXYNOS_SECOND_POINT_TRIM - EXYNOS_FIRST_POINT_TRIM) + + data->temp_error1; } /* @@ -275,120 +237,123 @@ static int temp_to_code(struct exynos_tmu_data *data, u8 temp) */ static int code_to_temp(struct exynos_tmu_data *data, u16 temp_code) { - struct exynos_tmu_platform_data *pdata = data->pdata; - int temp; - - switch (pdata->cal_type) { - case TYPE_TWO_POINT_TRIMMING: - temp = (temp_code - data->temp_error1) * - (pdata->second_point_trim - pdata->first_point_trim) / - (data->temp_error2 - data->temp_error1) + - pdata->first_point_trim; - break; - case TYPE_ONE_POINT_TRIMMING: - temp = temp_code - data->temp_error1 + pdata->first_point_trim; - break; - default: - temp = temp_code - pdata->default_temp_offset; - break; - } + if (data->cal_type == TYPE_ONE_POINT_TRIMMING) + return temp_code - data->temp_error1 + EXYNOS_FIRST_POINT_TRIM; - return temp; + return (temp_code - data->temp_error1) * + (EXYNOS_SECOND_POINT_TRIM - EXYNOS_FIRST_POINT_TRIM) / + (data->temp_error2 - data->temp_error1) + + EXYNOS_FIRST_POINT_TRIM; } static void sanitize_temp_error(struct exynos_tmu_data *data, u32 trim_info) { - struct exynos_tmu_platform_data *pdata = data->pdata; + u16 tmu_temp_mask = + (data->soc == SOC_ARCH_EXYNOS7) ? EXYNOS7_TMU_TEMP_MASK + : EXYNOS_TMU_TEMP_MASK; - data->temp_error1 = trim_info & EXYNOS_TMU_TEMP_MASK; + data->temp_error1 = trim_info & tmu_temp_mask; data->temp_error2 = ((trim_info >> EXYNOS_TRIMINFO_85_SHIFT) & EXYNOS_TMU_TEMP_MASK); if (!data->temp_error1 || - (pdata->min_efuse_value > data->temp_error1) || - (data->temp_error1 > pdata->max_efuse_value)) - data->temp_error1 = pdata->efuse_value & EXYNOS_TMU_TEMP_MASK; + (data->min_efuse_value > data->temp_error1) || + (data->temp_error1 > data->max_efuse_value)) + data->temp_error1 = data->efuse_value & EXYNOS_TMU_TEMP_MASK; if (!data->temp_error2) data->temp_error2 = - (pdata->efuse_value >> EXYNOS_TRIMINFO_85_SHIFT) & + (data->efuse_value >> EXYNOS_TRIMINFO_85_SHIFT) & EXYNOS_TMU_TEMP_MASK; } -static u32 get_th_reg(struct exynos_tmu_data *data, u32 threshold, bool falling) +static int exynos_tmu_initialize(struct platform_device *pdev) { - struct thermal_zone_device *tz = data->tzd; + struct exynos_tmu_data *data = platform_get_drvdata(pdev); + struct thermal_zone_device *tzd = data->tzd; const struct thermal_trip * const trips = - of_thermal_get_trip_points(tz); - unsigned long temp; - int i; + of_thermal_get_trip_points(tzd); + unsigned int status; + int ret = 0, temp, hyst; if (!trips) { - pr_err("%s: Cannot get trip points from of-thermal.c!\n", - __func__); - return 0; + dev_err(&pdev->dev, + "Cannot get trip points from device tree!\n"); + return -ENODEV; } - for (i = 0; i < of_thermal_get_ntrips(tz); i++) { - if (trips[i].type == THERMAL_TRIP_CRITICAL) - continue; - - temp = trips[i].temperature / MCELSIUS; - if (falling) - temp -= (trips[i].hysteresis / MCELSIUS); - else - threshold &= ~(0xff << 8 * i); - - threshold |= temp_to_code(data, temp) << 8 * i; + if (data->soc != SOC_ARCH_EXYNOS5433) /* FIXME */ + ret = tzd->ops->get_crit_temp(tzd, &temp); + if (ret) { + dev_err(&pdev->dev, + "No CRITICAL trip point defined in device tree!\n"); + goto out; } - return threshold; -} - -static int exynos_tmu_initialize(struct platform_device *pdev) -{ - struct exynos_tmu_data *data = platform_get_drvdata(pdev); - int ret; - - if (of_thermal_get_ntrips(data->tzd) > data->ntrip) { + if (of_thermal_get_ntrips(tzd) > data->ntrip) { dev_info(&pdev->dev, "More trip points than supported by this TMU.\n"); dev_info(&pdev->dev, "%d trip points should be configured in polling mode.\n", - (of_thermal_get_ntrips(data->tzd) - data->ntrip)); + (of_thermal_get_ntrips(tzd) - data->ntrip)); } mutex_lock(&data->lock); clk_enable(data->clk); if (!IS_ERR(data->clk_sec)) clk_enable(data->clk_sec); - ret = data->tmu_initialize(pdev); + + status = readb(data->base + EXYNOS_TMU_REG_STATUS); + if (!status) { + ret = -EBUSY; + } else { + int i, ntrips = + min_t(int, of_thermal_get_ntrips(tzd), data->ntrip); + + data->tmu_initialize(pdev); + + /* Write temperature code for rising and falling threshold */ + for (i = 0; i < ntrips; i++) { + /* Write temperature code for rising threshold */ + ret = tzd->ops->get_trip_temp(tzd, i, &temp); + if (ret) + goto err; + temp /= MCELSIUS; + data->tmu_set_trip_temp(data, i, temp); + + /* Write temperature code for falling threshold */ + ret = tzd->ops->get_trip_hyst(tzd, i, &hyst); + if (ret) + goto err; + hyst /= MCELSIUS; + data->tmu_set_trip_hyst(data, i, temp, hyst); + } + + data->tmu_clear_irqs(data); + } +err: clk_disable(data->clk); mutex_unlock(&data->lock); if (!IS_ERR(data->clk_sec)) clk_disable(data->clk_sec); - +out: return ret; } static u32 get_con_reg(struct exynos_tmu_data *data, u32 con) { - struct exynos_tmu_platform_data *pdata = data->pdata; - if (data->soc == SOC_ARCH_EXYNOS4412 || data->soc == SOC_ARCH_EXYNOS3250) con |= (EXYNOS4412_MUX_ADDR_VALUE << EXYNOS4412_MUX_ADDR_SHIFT); con &= ~(EXYNOS_TMU_REF_VOLTAGE_MASK << EXYNOS_TMU_REF_VOLTAGE_SHIFT); - con |= pdata->reference_voltage << EXYNOS_TMU_REF_VOLTAGE_SHIFT; + con |= data->reference_voltage << EXYNOS_TMU_REF_VOLTAGE_SHIFT; con &= ~(EXYNOS_TMU_BUF_SLOPE_SEL_MASK << EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT); - con |= (pdata->gain << EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT); + con |= (data->gain << EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT); - if (pdata->noise_cancel_mode) { - con &= ~(EXYNOS_TMU_TRIP_MODE_MASK << EXYNOS_TMU_TRIP_MODE_SHIFT); - con |= (pdata->noise_cancel_mode << EXYNOS_TMU_TRIP_MODE_SHIFT); - } + con &= ~(EXYNOS_TMU_TRIP_MODE_MASK << EXYNOS_TMU_TRIP_MODE_SHIFT); + con |= (EXYNOS_NOISE_CANCEL_MODE << EXYNOS_TMU_TRIP_MODE_SHIFT); return con; } @@ -405,65 +370,70 @@ static void exynos_tmu_control(struct platform_device *pdev, bool on) mutex_unlock(&data->lock); } -static int exynos4210_tmu_initialize(struct platform_device *pdev) +static void exynos4210_tmu_set_trip_temp(struct exynos_tmu_data *data, + int trip, u8 temp) { - struct exynos_tmu_data *data = platform_get_drvdata(pdev); - struct thermal_zone_device *tz = data->tzd; const struct thermal_trip * const trips = - of_thermal_get_trip_points(tz); - int ret = 0, threshold_code, i; - unsigned long reference, temp; - unsigned int status; + of_thermal_get_trip_points(data->tzd); + u8 ref, th_code; - if (!trips) { - pr_err("%s: Cannot get trip points from of-thermal.c!\n", - __func__); - ret = -ENODEV; - goto out; - } + ref = trips[0].temperature / MCELSIUS; - status = readb(data->base + EXYNOS_TMU_REG_STATUS); - if (!status) { - ret = -EBUSY; - goto out; + if (trip == 0) { + th_code = temp_to_code(data, ref); + writeb(th_code, data->base + EXYNOS4210_TMU_REG_THRESHOLD_TEMP); } + temp -= ref; + writeb(temp, data->base + EXYNOS4210_TMU_REG_TRIG_LEVEL0 + trip * 4); +} + +/* failing thresholds are not supported on Exynos4210 */ +static void exynos4210_tmu_set_trip_hyst(struct exynos_tmu_data *data, + int trip, u8 temp, u8 hyst) +{ +} + +static void exynos4210_tmu_initialize(struct platform_device *pdev) +{ + struct exynos_tmu_data *data = platform_get_drvdata(pdev); + sanitize_temp_error(data, readl(data->base + EXYNOS_TMU_REG_TRIMINFO)); +} - /* Write temperature code for threshold */ - reference = trips[0].temperature / MCELSIUS; - threshold_code = temp_to_code(data, reference); - if (threshold_code < 0) { - ret = threshold_code; - goto out; - } - writeb(threshold_code, data->base + EXYNOS4210_TMU_REG_THRESHOLD_TEMP); +static void exynos4412_tmu_set_trip_temp(struct exynos_tmu_data *data, + int trip, u8 temp) +{ + u32 th, con; - for (i = 0; i < of_thermal_get_ntrips(tz); i++) { - temp = trips[i].temperature / MCELSIUS; - writeb(temp - reference, data->base + - EXYNOS4210_TMU_REG_TRIG_LEVEL0 + i * 4); + th = readl(data->base + EXYNOS_THD_TEMP_RISE); + th &= ~(0xff << 8 * trip); + th |= temp_to_code(data, temp) << 8 * trip; + writel(th, data->base + EXYNOS_THD_TEMP_RISE); + + if (trip == 3) { + con = readl(data->base + EXYNOS_TMU_REG_CONTROL); + con |= (1 << EXYNOS_TMU_THERM_TRIP_EN_SHIFT); + writel(con, data->base + EXYNOS_TMU_REG_CONTROL); } +} - data->tmu_clear_irqs(data); -out: - return ret; +static void exynos4412_tmu_set_trip_hyst(struct exynos_tmu_data *data, + int trip, u8 temp, u8 hyst) +{ + u32 th; + + th = readl(data->base + EXYNOS_THD_TEMP_FALL); + th &= ~(0xff << 8 * trip); + if (hyst) + th |= temp_to_code(data, temp - hyst) << 8 * trip; + writel(th, data->base + EXYNOS_THD_TEMP_FALL); } -static int exynos4412_tmu_initialize(struct platform_device *pdev) +static void exynos4412_tmu_initialize(struct platform_device *pdev) { struct exynos_tmu_data *data = platform_get_drvdata(pdev); - const struct thermal_trip * const trips = - of_thermal_get_trip_points(data->tzd); - unsigned int status, trim_info, con, ctrl, rising_threshold; - int ret = 0, threshold_code, i; - unsigned long crit_temp = 0; - - status = readb(data->base + EXYNOS_TMU_REG_STATUS); - if (!status) { - ret = -EBUSY; - goto out; - } + unsigned int trim_info, ctrl; if (data->soc == SOC_ARCH_EXYNOS3250 || data->soc == SOC_ARCH_EXYNOS4412 || @@ -485,58 +455,53 @@ static int exynos4412_tmu_initialize(struct platform_device *pdev) trim_info = readl(data->base + EXYNOS_TMU_REG_TRIMINFO); sanitize_temp_error(data, trim_info); +} - /* Write temperature code for rising and falling threshold */ - rising_threshold = readl(data->base + EXYNOS_THD_TEMP_RISE); - rising_threshold = get_th_reg(data, rising_threshold, false); - writel(rising_threshold, data->base + EXYNOS_THD_TEMP_RISE); - writel(get_th_reg(data, 0, true), data->base + EXYNOS_THD_TEMP_FALL); - - data->tmu_clear_irqs(data); +static void exynos5433_tmu_set_trip_temp(struct exynos_tmu_data *data, + int trip, u8 temp) +{ + unsigned int reg_off, j; + u32 th; - /* if last threshold limit is also present */ - for (i = 0; i < of_thermal_get_ntrips(data->tzd); i++) { - if (trips[i].type == THERMAL_TRIP_CRITICAL) { - crit_temp = trips[i].temperature; - break; - } + if (trip > 3) { + reg_off = EXYNOS5433_THD_TEMP_RISE7_4; + j = trip - 4; + } else { + reg_off = EXYNOS5433_THD_TEMP_RISE3_0; + j = trip; } - if (i == of_thermal_get_ntrips(data->tzd)) { - pr_err("%s: No CRITICAL trip point defined at of-thermal.c!\n", - __func__); - ret = -EINVAL; - goto out; - } + th = readl(data->base + reg_off); + th &= ~(0xff << j * 8); + th |= (temp_to_code(data, temp) << j * 8); + writel(th, data->base + reg_off); +} - threshold_code = temp_to_code(data, crit_temp / MCELSIUS); - /* 1-4 level to be assigned in th0 reg */ - rising_threshold &= ~(0xff << 8 * i); - rising_threshold |= threshold_code << 8 * i; - writel(rising_threshold, data->base + EXYNOS_THD_TEMP_RISE); - con = readl(data->base + EXYNOS_TMU_REG_CONTROL); - con |= (1 << EXYNOS_TMU_THERM_TRIP_EN_SHIFT); - writel(con, data->base + EXYNOS_TMU_REG_CONTROL); +static void exynos5433_tmu_set_trip_hyst(struct exynos_tmu_data *data, + int trip, u8 temp, u8 hyst) +{ + unsigned int reg_off, j; + u32 th; -out: - return ret; + if (trip > 3) { + reg_off = EXYNOS5433_THD_TEMP_FALL7_4; + j = trip - 4; + } else { + reg_off = EXYNOS5433_THD_TEMP_FALL3_0; + j = trip; + } + + th = readl(data->base + reg_off); + th &= ~(0xff << j * 8); + th |= (temp_to_code(data, temp - hyst) << j * 8); + writel(th, data->base + reg_off); } -static int exynos5433_tmu_initialize(struct platform_device *pdev) +static void exynos5433_tmu_initialize(struct platform_device *pdev) { struct exynos_tmu_data *data = platform_get_drvdata(pdev); - struct exynos_tmu_platform_data *pdata = data->pdata; - struct thermal_zone_device *tz = data->tzd; - unsigned int status, trim_info; - unsigned int rising_threshold = 0, falling_threshold = 0; - int temp, temp_hist; - int ret = 0, threshold_code, i, sensor_id, cal_type; - - status = readb(data->base + EXYNOS_TMU_REG_STATUS); - if (!status) { - ret = -EBUSY; - goto out; - } + unsigned int trim_info; + int sensor_id, cal_type; trim_info = readl(data->base + EXYNOS_TMU_REG_TRIMINFO); sanitize_temp_error(data, trim_info); @@ -552,227 +517,84 @@ static int exynos5433_tmu_initialize(struct platform_device *pdev) >> EXYNOS5433_TRIMINFO_CALIB_SEL_SHIFT; switch (cal_type) { - case EXYNOS5433_TRIMINFO_ONE_POINT_TRIMMING: - pdata->cal_type = TYPE_ONE_POINT_TRIMMING; - break; case EXYNOS5433_TRIMINFO_TWO_POINT_TRIMMING: - pdata->cal_type = TYPE_TWO_POINT_TRIMMING; + data->cal_type = TYPE_TWO_POINT_TRIMMING; break; + case EXYNOS5433_TRIMINFO_ONE_POINT_TRIMMING: default: - pdata->cal_type = TYPE_ONE_POINT_TRIMMING; + data->cal_type = TYPE_ONE_POINT_TRIMMING; break; } dev_info(&pdev->dev, "Calibration type is %d-point calibration\n", cal_type ? 2 : 1); - - /* Write temperature code for rising and falling threshold */ - for (i = 0; i < of_thermal_get_ntrips(tz); i++) { - int rising_reg_offset, falling_reg_offset; - int j = 0; - - switch (i) { - case 0: - case 1: - case 2: - case 3: - rising_reg_offset = EXYNOS5433_THD_TEMP_RISE3_0; - falling_reg_offset = EXYNOS5433_THD_TEMP_FALL3_0; - j = i; - break; - case 4: - case 5: - case 6: - case 7: - rising_reg_offset = EXYNOS5433_THD_TEMP_RISE7_4; - falling_reg_offset = EXYNOS5433_THD_TEMP_FALL7_4; - j = i - 4; - break; - default: - continue; - } - - /* Write temperature code for rising threshold */ - tz->ops->get_trip_temp(tz, i, &temp); - temp /= MCELSIUS; - threshold_code = temp_to_code(data, temp); - - rising_threshold = readl(data->base + rising_reg_offset); - rising_threshold |= (threshold_code << j * 8); - writel(rising_threshold, data->base + rising_reg_offset); - - /* Write temperature code for falling threshold */ - tz->ops->get_trip_hyst(tz, i, &temp_hist); - temp_hist = temp - (temp_hist / MCELSIUS); - threshold_code = temp_to_code(data, temp_hist); - - falling_threshold = readl(data->base + falling_reg_offset); - falling_threshold &= ~(0xff << j * 8); - falling_threshold |= (threshold_code << j * 8); - writel(falling_threshold, data->base + falling_reg_offset); - } - - data->tmu_clear_irqs(data); -out: - return ret; } -static int exynos5440_tmu_initialize(struct platform_device *pdev) +static void exynos7_tmu_set_trip_temp(struct exynos_tmu_data *data, + int trip, u8 temp) { - struct exynos_tmu_data *data = platform_get_drvdata(pdev); - unsigned int trim_info = 0, con, rising_threshold; - int threshold_code; - int crit_temp = 0; + unsigned int reg_off, bit_off; + u32 th; - /* - * For exynos5440 soc triminfo value is swapped between TMU0 and - * TMU2, so the below logic is needed. - */ - switch (data->id) { - case 0: - trim_info = readl(data->base + EXYNOS5440_EFUSE_SWAP_OFFSET + - EXYNOS5440_TMU_S0_7_TRIM); - break; - case 1: - trim_info = readl(data->base + EXYNOS5440_TMU_S0_7_TRIM); - break; - case 2: - trim_info = readl(data->base - EXYNOS5440_EFUSE_SWAP_OFFSET + - EXYNOS5440_TMU_S0_7_TRIM); - } - sanitize_temp_error(data, trim_info); + reg_off = ((7 - trip) / 2) * 4; + bit_off = ((8 - trip) % 2); - /* Write temperature code for rising and falling threshold */ - rising_threshold = readl(data->base + EXYNOS5440_TMU_S0_7_TH0); - rising_threshold = get_th_reg(data, rising_threshold, false); - writel(rising_threshold, data->base + EXYNOS5440_TMU_S0_7_TH0); - writel(0, data->base + EXYNOS5440_TMU_S0_7_TH1); + th = readl(data->base + EXYNOS7_THD_TEMP_RISE7_6 + reg_off); + th &= ~(EXYNOS7_TMU_TEMP_MASK << (16 * bit_off)); + th |= temp_to_code(data, temp) << (16 * bit_off); + writel(th, data->base + EXYNOS7_THD_TEMP_RISE7_6 + reg_off); +} - data->tmu_clear_irqs(data); +static void exynos7_tmu_set_trip_hyst(struct exynos_tmu_data *data, + int trip, u8 temp, u8 hyst) +{ + unsigned int reg_off, bit_off; + u32 th; - /* if last threshold limit is also present */ - if (!data->tzd->ops->get_crit_temp(data->tzd, &crit_temp)) { - threshold_code = temp_to_code(data, crit_temp / MCELSIUS); - /* 5th level to be assigned in th2 reg */ - rising_threshold = - threshold_code << EXYNOS5440_TMU_TH_RISE4_SHIFT; - writel(rising_threshold, data->base + EXYNOS5440_TMU_S0_7_TH2); - con = readl(data->base + EXYNOS5440_TMU_S0_7_CTRL); - con |= (1 << EXYNOS_TMU_THERM_TRIP_EN_SHIFT); - writel(con, data->base + EXYNOS5440_TMU_S0_7_CTRL); - } - /* Clear the PMIN in the common TMU register */ - if (!data->id) - writel(0, data->base_second + EXYNOS5440_TMU_PMIN); + reg_off = ((7 - trip) / 2) * 4; + bit_off = ((8 - trip) % 2); - return 0; + th = readl(data->base + EXYNOS7_THD_TEMP_FALL7_6 + reg_off); + th &= ~(EXYNOS7_TMU_TEMP_MASK << (16 * bit_off)); + th |= temp_to_code(data, temp - hyst) << (16 * bit_off); + writel(th, data->base + EXYNOS7_THD_TEMP_FALL7_6 + reg_off); } -static int exynos7_tmu_initialize(struct platform_device *pdev) +static void exynos7_tmu_initialize(struct platform_device *pdev) { struct exynos_tmu_data *data = platform_get_drvdata(pdev); - struct thermal_zone_device *tz = data->tzd; - struct exynos_tmu_platform_data *pdata = data->pdata; - unsigned int status, trim_info; - unsigned int rising_threshold = 0, falling_threshold = 0; - int ret = 0, threshold_code, i; - int temp, temp_hist; - unsigned int reg_off, bit_off; - - status = readb(data->base + EXYNOS_TMU_REG_STATUS); - if (!status) { - ret = -EBUSY; - goto out; - } + unsigned int trim_info; trim_info = readl(data->base + EXYNOS_TMU_REG_TRIMINFO); - - data->temp_error1 = trim_info & EXYNOS7_TMU_TEMP_MASK; - if (!data->temp_error1 || - (pdata->min_efuse_value > data->temp_error1) || - (data->temp_error1 > pdata->max_efuse_value)) - data->temp_error1 = pdata->efuse_value & EXYNOS_TMU_TEMP_MASK; - - /* Write temperature code for rising and falling threshold */ - for (i = (of_thermal_get_ntrips(tz) - 1); i >= 0; i--) { - /* - * On exynos7 there are 4 rising and 4 falling threshold - * registers (0x50-0x5c and 0x60-0x6c respectively). Each - * register holds the value of two threshold levels (at bit - * offsets 0 and 16). Based on the fact that there are atmost - * eight possible trigger levels, calculate the register and - * bit offsets where the threshold levels are to be written. - * - * e.g. EXYNOS7_THD_TEMP_RISE7_6 (0x50) - * [24:16] - Threshold level 7 - * [8:0] - Threshold level 6 - * e.g. EXYNOS7_THD_TEMP_RISE5_4 (0x54) - * [24:16] - Threshold level 5 - * [8:0] - Threshold level 4 - * - * and similarly for falling thresholds. - * - * Based on the above, calculate the register and bit offsets - * for rising/falling threshold levels and populate them. - */ - reg_off = ((7 - i) / 2) * 4; - bit_off = ((8 - i) % 2); - - tz->ops->get_trip_temp(tz, i, &temp); - temp /= MCELSIUS; - - tz->ops->get_trip_hyst(tz, i, &temp_hist); - temp_hist = temp - (temp_hist / MCELSIUS); - - /* Set 9-bit temperature code for rising threshold levels */ - threshold_code = temp_to_code(data, temp); - rising_threshold = readl(data->base + - EXYNOS7_THD_TEMP_RISE7_6 + reg_off); - rising_threshold &= ~(EXYNOS7_TMU_TEMP_MASK << (16 * bit_off)); - rising_threshold |= threshold_code << (16 * bit_off); - writel(rising_threshold, - data->base + EXYNOS7_THD_TEMP_RISE7_6 + reg_off); - - /* Set 9-bit temperature code for falling threshold levels */ - threshold_code = temp_to_code(data, temp_hist); - falling_threshold &= ~(EXYNOS7_TMU_TEMP_MASK << (16 * bit_off)); - falling_threshold |= threshold_code << (16 * bit_off); - writel(falling_threshold, - data->base + EXYNOS7_THD_TEMP_FALL7_6 + reg_off); - } - - data->tmu_clear_irqs(data); -out: - return ret; + sanitize_temp_error(data, trim_info); } static void exynos4210_tmu_control(struct platform_device *pdev, bool on) { struct exynos_tmu_data *data = platform_get_drvdata(pdev); struct thermal_zone_device *tz = data->tzd; - unsigned int con, interrupt_en; + unsigned int con, interrupt_en = 0, i; con = get_con_reg(data, readl(data->base + EXYNOS_TMU_REG_CONTROL)); if (on) { - con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT); - interrupt_en = - (of_thermal_is_trip_valid(tz, 3) - << EXYNOS_TMU_INTEN_RISE3_SHIFT) | - (of_thermal_is_trip_valid(tz, 2) - << EXYNOS_TMU_INTEN_RISE2_SHIFT) | - (of_thermal_is_trip_valid(tz, 1) - << EXYNOS_TMU_INTEN_RISE1_SHIFT) | - (of_thermal_is_trip_valid(tz, 0) - << EXYNOS_TMU_INTEN_RISE0_SHIFT); + for (i = 0; i < data->ntrip; i++) { + if (!of_thermal_is_trip_valid(tz, i)) + continue; + + interrupt_en |= + (1 << (EXYNOS_TMU_INTEN_RISE0_SHIFT + i * 4)); + } if (data->soc != SOC_ARCH_EXYNOS4210) interrupt_en |= interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT; + + con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT); } else { con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT); - interrupt_en = 0; /* Disable all interrupts */ } + writel(interrupt_en, data->base + EXYNOS_TMU_REG_INTEN); writel(con, data->base + EXYNOS_TMU_REG_CONTROL); } @@ -781,36 +603,25 @@ static void exynos5433_tmu_control(struct platform_device *pdev, bool on) { struct exynos_tmu_data *data = platform_get_drvdata(pdev); struct thermal_zone_device *tz = data->tzd; - unsigned int con, interrupt_en, pd_det_en; + unsigned int con, interrupt_en = 0, pd_det_en, i; con = get_con_reg(data, readl(data->base + EXYNOS_TMU_REG_CONTROL)); if (on) { - con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT); - interrupt_en = - (of_thermal_is_trip_valid(tz, 7) - << EXYNOS7_TMU_INTEN_RISE7_SHIFT) | - (of_thermal_is_trip_valid(tz, 6) - << EXYNOS7_TMU_INTEN_RISE6_SHIFT) | - (of_thermal_is_trip_valid(tz, 5) - << EXYNOS7_TMU_INTEN_RISE5_SHIFT) | - (of_thermal_is_trip_valid(tz, 4) - << EXYNOS7_TMU_INTEN_RISE4_SHIFT) | - (of_thermal_is_trip_valid(tz, 3) - << EXYNOS7_TMU_INTEN_RISE3_SHIFT) | - (of_thermal_is_trip_valid(tz, 2) - << EXYNOS7_TMU_INTEN_RISE2_SHIFT) | - (of_thermal_is_trip_valid(tz, 1) - << EXYNOS7_TMU_INTEN_RISE1_SHIFT) | - (of_thermal_is_trip_valid(tz, 0) - << EXYNOS7_TMU_INTEN_RISE0_SHIFT); + for (i = 0; i < data->ntrip; i++) { + if (!of_thermal_is_trip_valid(tz, i)) + continue; + + interrupt_en |= + (1 << (EXYNOS7_TMU_INTEN_RISE0_SHIFT + i)); + } interrupt_en |= interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT; - } else { + + con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT); + } else con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT); - interrupt_en = 0; /* Disable all interrupts */ - } pd_det_en = on ? EXYNOS5433_PD_DET_EN : 0; @@ -819,70 +630,31 @@ static void exynos5433_tmu_control(struct platform_device *pdev, bool on) writel(con, data->base + EXYNOS_TMU_REG_CONTROL); } -static void exynos5440_tmu_control(struct platform_device *pdev, bool on) -{ - struct exynos_tmu_data *data = platform_get_drvdata(pdev); - struct thermal_zone_device *tz = data->tzd; - unsigned int con, interrupt_en; - - con = get_con_reg(data, readl(data->base + EXYNOS5440_TMU_S0_7_CTRL)); - - if (on) { - con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT); - interrupt_en = - (of_thermal_is_trip_valid(tz, 3) - << EXYNOS5440_TMU_INTEN_RISE3_SHIFT) | - (of_thermal_is_trip_valid(tz, 2) - << EXYNOS5440_TMU_INTEN_RISE2_SHIFT) | - (of_thermal_is_trip_valid(tz, 1) - << EXYNOS5440_TMU_INTEN_RISE1_SHIFT) | - (of_thermal_is_trip_valid(tz, 0) - << EXYNOS5440_TMU_INTEN_RISE0_SHIFT); - interrupt_en |= - interrupt_en << EXYNOS5440_TMU_INTEN_FALL0_SHIFT; - } else { - con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT); - interrupt_en = 0; /* Disable all interrupts */ - } - writel(interrupt_en, data->base + EXYNOS5440_TMU_S0_7_IRQEN); - writel(con, data->base + EXYNOS5440_TMU_S0_7_CTRL); -} - static void exynos7_tmu_control(struct platform_device *pdev, bool on) { struct exynos_tmu_data *data = platform_get_drvdata(pdev); struct thermal_zone_device *tz = data->tzd; - unsigned int con, interrupt_en; + unsigned int con, interrupt_en = 0, i; con = get_con_reg(data, readl(data->base + EXYNOS_TMU_REG_CONTROL)); if (on) { - con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT); - con |= (1 << EXYNOS7_PD_DET_EN_SHIFT); - interrupt_en = - (of_thermal_is_trip_valid(tz, 7) - << EXYNOS7_TMU_INTEN_RISE7_SHIFT) | - (of_thermal_is_trip_valid(tz, 6) - << EXYNOS7_TMU_INTEN_RISE6_SHIFT) | - (of_thermal_is_trip_valid(tz, 5) - << EXYNOS7_TMU_INTEN_RISE5_SHIFT) | - (of_thermal_is_trip_valid(tz, 4) - << EXYNOS7_TMU_INTEN_RISE4_SHIFT) | - (of_thermal_is_trip_valid(tz, 3) - << EXYNOS7_TMU_INTEN_RISE3_SHIFT) | - (of_thermal_is_trip_valid(tz, 2) - << EXYNOS7_TMU_INTEN_RISE2_SHIFT) | - (of_thermal_is_trip_valid(tz, 1) - << EXYNOS7_TMU_INTEN_RISE1_SHIFT) | - (of_thermal_is_trip_valid(tz, 0) - << EXYNOS7_TMU_INTEN_RISE0_SHIFT); + for (i = 0; i < data->ntrip; i++) { + if (!of_thermal_is_trip_valid(tz, i)) + continue; + + interrupt_en |= + (1 << (EXYNOS7_TMU_INTEN_RISE0_SHIFT + i)); + } interrupt_en |= interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT; + + con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT); + con |= (1 << EXYNOS7_PD_DET_EN_SHIFT); } else { con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT); con &= ~(1 << EXYNOS7_PD_DET_EN_SHIFT); - interrupt_en = 0; /* Disable all interrupts */ } writel(interrupt_en, data->base + EXYNOS7_TMU_REG_INTEN); @@ -896,6 +668,12 @@ static int exynos_get_temp(void *p, int *temp) if (!data || !data->tmu_read || !data->enabled) return -EINVAL; + else if (!data->enabled) + /* + * Called too early, probably + * from thermal_zone_of_sensor_register(). + */ + return -EAGAIN; mutex_lock(&data->lock); clk_enable(data->clk); @@ -919,10 +697,8 @@ static u32 get_emul_con_reg(struct exynos_tmu_data *data, unsigned int val, if (temp) { temp /= MCELSIUS; - if (data->soc != SOC_ARCH_EXYNOS5440) { - val &= ~(EXYNOS_EMUL_TIME_MASK << EXYNOS_EMUL_TIME_SHIFT); - val |= (EXYNOS_EMUL_TIME << EXYNOS_EMUL_TIME_SHIFT); - } + val &= ~(EXYNOS_EMUL_TIME_MASK << EXYNOS_EMUL_TIME_SHIFT); + val |= (EXYNOS_EMUL_TIME << EXYNOS_EMUL_TIME_SHIFT); if (data->soc == SOC_ARCH_EXYNOS7) { val &= ~(EXYNOS7_EMUL_DATA_MASK << EXYNOS7_EMUL_DATA_SHIFT); @@ -963,16 +739,6 @@ static void exynos4412_tmu_set_emulation(struct exynos_tmu_data *data, writel(val, data->base + emul_con); } -static void exynos5440_tmu_set_emulation(struct exynos_tmu_data *data, - int temp) -{ - unsigned int val; - - val = readl(data->base + EXYNOS5440_TMU_S0_7_DEBUG); - val = get_emul_con_reg(data, val, temp); - writel(val, data->base + EXYNOS5440_TMU_S0_7_DEBUG); -} - static int exynos_tmu_set_emulation(void *drv_data, int temp) { struct exynos_tmu_data *data = drv_data; @@ -995,7 +761,6 @@ out: } #else #define exynos4412_tmu_set_emulation NULL -#define exynos5440_tmu_set_emulation NULL static int exynos_tmu_set_emulation(void *drv_data, int temp) { return -EINVAL; } #endif /* CONFIG_THERMAL_EMULATION */ @@ -1013,11 +778,6 @@ static int exynos4412_tmu_read(struct exynos_tmu_data *data) return readb(data->base + EXYNOS_TMU_REG_CURRENT_TEMP); } -static int exynos5440_tmu_read(struct exynos_tmu_data *data) -{ - return readb(data->base + EXYNOS5440_TMU_S0_7_TEMP); -} - static int exynos7_tmu_read(struct exynos_tmu_data *data) { return readw(data->base + EXYNOS_TMU_REG_CURRENT_TEMP) & @@ -1028,20 +788,14 @@ static void exynos_tmu_work(struct work_struct *work) { struct exynos_tmu_data *data = container_of(work, struct exynos_tmu_data, irq_work); - unsigned int val_type; if (!IS_ERR(data->clk_sec)) clk_enable(data->clk_sec); - /* Find which sensor generated this interrupt */ - if (data->soc == SOC_ARCH_EXYNOS5440) { - val_type = readl(data->base_second + EXYNOS5440_TMU_IRQ_STATUS); - if (!((val_type >> data->id) & 0x1)) - goto out; - } if (!IS_ERR(data->clk_sec)) clk_disable(data->clk_sec); - exynos_report_trigger(data); + thermal_zone_device_update(data->tzd, THERMAL_EVENT_UNSPECIFIED); + mutex_lock(&data->lock); clk_enable(data->clk); @@ -1050,7 +804,6 @@ static void exynos_tmu_work(struct work_struct *work) clk_disable(data->clk); mutex_unlock(&data->lock); -out: enable_irq(data->irq); } @@ -1085,15 +838,6 @@ static void exynos4210_tmu_clear_irqs(struct exynos_tmu_data *data) writel(val_irq, data->base + tmu_intclear); } -static void exynos5440_tmu_clear_irqs(struct exynos_tmu_data *data) -{ - unsigned int val_irq; - - val_irq = readl(data->base + EXYNOS5440_TMU_S0_7_IRQ); - /* clear the interrupts */ - writel(val_irq, data->base + EXYNOS5440_TMU_S0_7_IRQ); -} - static irqreturn_t exynos_tmu_irq(int irq, void *id) { struct exynos_tmu_data *data = id; @@ -1105,86 +849,41 @@ static irqreturn_t exynos_tmu_irq(int irq, void *id) } static const struct of_device_id exynos_tmu_match[] = { - { .compatible = "samsung,exynos3250-tmu", }, - { .compatible = "samsung,exynos4210-tmu", }, - { .compatible = "samsung,exynos4412-tmu", }, - { .compatible = "samsung,exynos5250-tmu", }, - { .compatible = "samsung,exynos5260-tmu", }, - { .compatible = "samsung,exynos5420-tmu", }, - { .compatible = "samsung,exynos5420-tmu-ext-triminfo", }, - { .compatible = "samsung,exynos5433-tmu", }, - { .compatible = "samsung,exynos5440-tmu", }, - { .compatible = "samsung,exynos7-tmu", }, - { /* sentinel */ }, + { + .compatible = "samsung,exynos3250-tmu", + .data = (const void *)SOC_ARCH_EXYNOS3250, + }, { + .compatible = "samsung,exynos4210-tmu", + .data = (const void *)SOC_ARCH_EXYNOS4210, + }, { + .compatible = "samsung,exynos4412-tmu", + .data = (const void *)SOC_ARCH_EXYNOS4412, + }, { + .compatible = "samsung,exynos5250-tmu", + .data = (const void *)SOC_ARCH_EXYNOS5250, + }, { + .compatible = "samsung,exynos5260-tmu", + .data = (const void *)SOC_ARCH_EXYNOS5260, + }, { + .compatible = "samsung,exynos5420-tmu", + .data = (const void *)SOC_ARCH_EXYNOS5420, + }, { + .compatible = "samsung,exynos5420-tmu-ext-triminfo", + .data = (const void *)SOC_ARCH_EXYNOS5420_TRIMINFO, + }, { + .compatible = "samsung,exynos5433-tmu", + .data = (const void *)SOC_ARCH_EXYNOS5433, + }, { + .compatible = "samsung,exynos7-tmu", + .data = (const void *)SOC_ARCH_EXYNOS7, + }, + { }, }; MODULE_DEVICE_TABLE(of, exynos_tmu_match); -static int exynos_of_get_soc_type(struct device_node *np) -{ - if (of_device_is_compatible(np, "samsung,exynos3250-tmu")) - return SOC_ARCH_EXYNOS3250; - else if (of_device_is_compatible(np, "samsung,exynos4210-tmu")) - return SOC_ARCH_EXYNOS4210; - else if (of_device_is_compatible(np, "samsung,exynos4412-tmu")) - return SOC_ARCH_EXYNOS4412; - else if (of_device_is_compatible(np, "samsung,exynos5250-tmu")) - return SOC_ARCH_EXYNOS5250; - else if (of_device_is_compatible(np, "samsung,exynos5260-tmu")) - return SOC_ARCH_EXYNOS5260; - else if (of_device_is_compatible(np, "samsung,exynos5420-tmu")) - return SOC_ARCH_EXYNOS5420; - else if (of_device_is_compatible(np, - "samsung,exynos5420-tmu-ext-triminfo")) - return SOC_ARCH_EXYNOS5420_TRIMINFO; - else if (of_device_is_compatible(np, "samsung,exynos5433-tmu")) - return SOC_ARCH_EXYNOS5433; - else if (of_device_is_compatible(np, "samsung,exynos5440-tmu")) - return SOC_ARCH_EXYNOS5440; - else if (of_device_is_compatible(np, "samsung,exynos7-tmu")) - return SOC_ARCH_EXYNOS7; - - return -EINVAL; -} - -static int exynos_of_sensor_conf(struct device_node *np, - struct exynos_tmu_platform_data *pdata) -{ - u32 value; - int ret; - - of_node_get(np); - - ret = of_property_read_u32(np, "samsung,tmu_gain", &value); - pdata->gain = (u8)value; - of_property_read_u32(np, "samsung,tmu_reference_voltage", &value); - pdata->reference_voltage = (u8)value; - of_property_read_u32(np, "samsung,tmu_noise_cancel_mode", &value); - pdata->noise_cancel_mode = (u8)value; - - of_property_read_u32(np, "samsung,tmu_efuse_value", - &pdata->efuse_value); - of_property_read_u32(np, "samsung,tmu_min_efuse_value", - &pdata->min_efuse_value); - of_property_read_u32(np, "samsung,tmu_max_efuse_value", - &pdata->max_efuse_value); - - of_property_read_u32(np, "samsung,tmu_first_point_trim", &value); - pdata->first_point_trim = (u8)value; - of_property_read_u32(np, "samsung,tmu_second_point_trim", &value); - pdata->second_point_trim = (u8)value; - of_property_read_u32(np, "samsung,tmu_default_temp_offset", &value); - pdata->default_temp_offset = (u8)value; - - of_property_read_u32(np, "samsung,tmu_cal_type", &pdata->cal_type); - - of_node_put(np); - return 0; -} - static int exynos_map_dt_data(struct platform_device *pdev) { struct exynos_tmu_data *data = platform_get_drvdata(pdev); - struct exynos_tmu_platform_data *pdata; struct resource res; if (!data || !pdev->dev.of_node) @@ -1211,23 +910,22 @@ static int exynos_map_dt_data(struct platform_device *pdev) return -EADDRNOTAVAIL; } - pdata = devm_kzalloc(&pdev->dev, - sizeof(struct exynos_tmu_platform_data), - GFP_KERNEL); - if (!pdata) - return -ENOMEM; - - exynos_of_sensor_conf(pdev->dev.of_node, pdata); - data->pdata = pdata; - data->soc = exynos_of_get_soc_type(pdev->dev.of_node); + data->soc = (enum soc_type)of_device_get_match_data(&pdev->dev); switch (data->soc) { case SOC_ARCH_EXYNOS4210: + data->tmu_set_trip_temp = exynos4210_tmu_set_trip_temp; + data->tmu_set_trip_hyst = exynos4210_tmu_set_trip_hyst; data->tmu_initialize = exynos4210_tmu_initialize; data->tmu_control = exynos4210_tmu_control; data->tmu_read = exynos4210_tmu_read; data->tmu_clear_irqs = exynos4210_tmu_clear_irqs; data->ntrip = 4; + data->gain = 15; + data->reference_voltage = 7; + data->efuse_value = 55; + data->min_efuse_value = 40; + data->max_efuse_value = 100; break; case SOC_ARCH_EXYNOS3250: case SOC_ARCH_EXYNOS4412: @@ -1235,48 +933,69 @@ static int exynos_map_dt_data(struct platform_device *pdev) case SOC_ARCH_EXYNOS5260: case SOC_ARCH_EXYNOS5420: case SOC_ARCH_EXYNOS5420_TRIMINFO: + data->tmu_set_trip_temp = exynos4412_tmu_set_trip_temp; + data->tmu_set_trip_hyst = exynos4412_tmu_set_trip_hyst; data->tmu_initialize = exynos4412_tmu_initialize; data->tmu_control = exynos4210_tmu_control; data->tmu_read = exynos4412_tmu_read; data->tmu_set_emulation = exynos4412_tmu_set_emulation; data->tmu_clear_irqs = exynos4210_tmu_clear_irqs; data->ntrip = 4; + data->gain = 8; + data->reference_voltage = 16; + data->efuse_value = 55; + if (data->soc != SOC_ARCH_EXYNOS5420 && + data->soc != SOC_ARCH_EXYNOS5420_TRIMINFO) + data->min_efuse_value = 40; + else + data->min_efuse_value = 0; + data->max_efuse_value = 100; break; case SOC_ARCH_EXYNOS5433: + data->tmu_set_trip_temp = exynos5433_tmu_set_trip_temp; + data->tmu_set_trip_hyst = exynos5433_tmu_set_trip_hyst; data->tmu_initialize = exynos5433_tmu_initialize; data->tmu_control = exynos5433_tmu_control; data->tmu_read = exynos4412_tmu_read; data->tmu_set_emulation = exynos4412_tmu_set_emulation; data->tmu_clear_irqs = exynos4210_tmu_clear_irqs; data->ntrip = 8; - break; - case SOC_ARCH_EXYNOS5440: - data->tmu_initialize = exynos5440_tmu_initialize; - data->tmu_control = exynos5440_tmu_control; - data->tmu_read = exynos5440_tmu_read; - data->tmu_set_emulation = exynos5440_tmu_set_emulation; - data->tmu_clear_irqs = exynos5440_tmu_clear_irqs; - data->ntrip = 4; + data->gain = 8; + if (res.start == EXYNOS5433_G3D_BASE) + data->reference_voltage = 23; + else + data->reference_voltage = 16; + data->efuse_value = 75; + data->min_efuse_value = 40; + data->max_efuse_value = 150; break; case SOC_ARCH_EXYNOS7: + data->tmu_set_trip_temp = exynos7_tmu_set_trip_temp; + data->tmu_set_trip_hyst = exynos7_tmu_set_trip_hyst; data->tmu_initialize = exynos7_tmu_initialize; data->tmu_control = exynos7_tmu_control; data->tmu_read = exynos7_tmu_read; data->tmu_set_emulation = exynos4412_tmu_set_emulation; data->tmu_clear_irqs = exynos4210_tmu_clear_irqs; data->ntrip = 8; + data->gain = 9; + data->reference_voltage = 17; + data->efuse_value = 75; + data->min_efuse_value = 15; + data->max_efuse_value = 100; break; default: dev_err(&pdev->dev, "Platform not supported\n"); return -EINVAL; } + data->cal_type = TYPE_ONE_POINT_TRIMMING; + /* * Check if the TMU shares some registers and then try to map the * memory of common registers. */ - if (data->soc != SOC_ARCH_EXYNOS5420_TRIMINFO && - data->soc != SOC_ARCH_EXYNOS5440) + if (data->soc != SOC_ARCH_EXYNOS5420_TRIMINFO) return 0; if (of_address_to_resource(pdev->dev.of_node, 1, &res)) { diff --git a/drivers/thermal/samsung/exynos_tmu.h b/drivers/thermal/samsung/exynos_tmu.h deleted file mode 100644 index 5149c2a3030c..000000000000 --- a/drivers/thermal/samsung/exynos_tmu.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * exynos_tmu.h - Samsung EXYNOS TMU (Thermal Management Unit) - * - * Copyright (C) 2011 Samsung Electronics - * Donggeun Kim <dg77.kim@samsung.com> - * Amit Daniel Kachhap <amit.daniel@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _EXYNOS_TMU_H -#define _EXYNOS_TMU_H -#include <linux/cpu_cooling.h> -#include <dt-bindings/thermal/thermal_exynos.h> - -enum soc_type { - SOC_ARCH_EXYNOS3250 = 1, - SOC_ARCH_EXYNOS4210, - SOC_ARCH_EXYNOS4412, - SOC_ARCH_EXYNOS5250, - SOC_ARCH_EXYNOS5260, - SOC_ARCH_EXYNOS5420, - SOC_ARCH_EXYNOS5420_TRIMINFO, - SOC_ARCH_EXYNOS5433, - SOC_ARCH_EXYNOS5440, - SOC_ARCH_EXYNOS7, -}; - -/** - * struct exynos_tmu_platform_data - * @gain: gain of amplifier in the positive-TC generator block - * 0 < gain <= 15 - * @reference_voltage: reference voltage of amplifier - * in the positive-TC generator block - * 0 < reference_voltage <= 31 - * @noise_cancel_mode: noise cancellation mode - * 000, 100, 101, 110 and 111 can be different modes - * @type: determines the type of SOC - * @efuse_value: platform defined fuse value - * @min_efuse_value: minimum valid trimming data - * @max_efuse_value: maximum valid trimming data - * @default_temp_offset: default temperature offset in case of no trimming - * @cal_type: calibration type for temperature - * - * This structure is required for configuration of exynos_tmu driver. - */ -struct exynos_tmu_platform_data { - u8 gain; - u8 reference_voltage; - u8 noise_cancel_mode; - - u32 efuse_value; - u32 min_efuse_value; - u32 max_efuse_value; - u8 first_point_trim; - u8 second_point_trim; - u8 default_temp_offset; - - enum soc_type type; - u32 cal_type; -}; - -#endif /* _EXYNOS_TMU_H */ diff --git a/drivers/thermal/tegra/soctherm.c b/drivers/thermal/tegra/soctherm.c index 455b58ce2652..ed28110a3535 100644 --- a/drivers/thermal/tegra/soctherm.c +++ b/drivers/thermal/tegra/soctherm.c @@ -241,31 +241,6 @@ struct tegra_soctherm { }; /** - * clk_writel() - writes a value to a CAR register - * @ts: pointer to a struct tegra_soctherm - * @v: the value to write - * @reg: the register offset - * - * Writes @v to @reg. No return value. - */ -static inline void clk_writel(struct tegra_soctherm *ts, u32 value, u32 reg) -{ - writel(value, (ts->clk_regs + reg)); -} - -/** - * clk_readl() - reads specified register from CAR IP block - * @ts: pointer to a struct tegra_soctherm - * @reg: register address to be read - * - * Return: the value of the register - */ -static inline u32 clk_readl(struct tegra_soctherm *ts, u32 reg) -{ - return readl(ts->clk_regs + reg); -} - -/** * ccroc_writel() - writes a value to a CCROC register * @ts: pointer to a struct tegra_soctherm * @v: the value to write @@ -926,7 +901,7 @@ static int throt_set_cdev_state(struct thermal_cooling_device *cdev, return 0; } -static struct thermal_cooling_device_ops throt_cooling_ops = { +static const struct thermal_cooling_device_ops throt_cooling_ops = { .get_max_state = throt_get_cdev_max_state, .get_cur_state = throt_get_cdev_cur_state, .set_cur_state = throt_set_cdev_state, @@ -1207,9 +1182,9 @@ static void tegra_soctherm_throttle(struct device *dev) } else { writel(v, ts->regs + THROT_GLOBAL_CFG); - v = clk_readl(ts, CAR_SUPER_CCLKG_DIVIDER); + v = readl(ts->clk_regs + CAR_SUPER_CCLKG_DIVIDER); v = REG_SET_MASK(v, CDIVG_USE_THERM_CONTROLS_MASK, 1); - clk_writel(ts, v, CAR_SUPER_CCLKG_DIVIDER); + writel(v, ts->clk_regs + CAR_SUPER_CCLKG_DIVIDER); } /* initialize stats collection */ @@ -1343,8 +1318,8 @@ static int tegra_soctherm_probe(struct platform_device *pdev) return PTR_ERR(tegra->clock_soctherm); } - tegra->calib = devm_kzalloc(&pdev->dev, - sizeof(u32) * soc->num_tsensors, + tegra->calib = devm_kcalloc(&pdev->dev, + soc->num_tsensors, sizeof(u32), GFP_KERNEL); if (!tegra->calib) return -ENOMEM; @@ -1363,8 +1338,8 @@ static int tegra_soctherm_probe(struct platform_device *pdev) return err; } - tegra->thermctl_tzs = devm_kzalloc(&pdev->dev, - sizeof(*z) * soc->num_ttgs, + tegra->thermctl_tzs = devm_kcalloc(&pdev->dev, + soc->num_ttgs, sizeof(*z), GFP_KERNEL); if (!tegra->thermctl_tzs) return -ENOMEM; diff --git a/drivers/thermal/thermal-generic-adc.c b/drivers/thermal/thermal-generic-adc.c index 46d3005335c7..bf1c628d4a7a 100644 --- a/drivers/thermal/thermal-generic-adc.c +++ b/drivers/thermal/thermal-generic-adc.c @@ -87,8 +87,9 @@ static int gadc_thermal_read_linear_lookup_table(struct device *dev, return -EINVAL; } - gti->lookup_table = devm_kzalloc(dev, sizeof(*gti->lookup_table) * - ntable, GFP_KERNEL); + gti->lookup_table = devm_kcalloc(dev, + ntable, sizeof(*gti->lookup_table), + GFP_KERNEL); if (!gti->lookup_table) return -ENOMEM; diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index d64325e078db..6ab982309e6a 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * thermal.c - Generic Thermal Management Sysfs support. * * Copyright (C) 2008 Intel Corp * Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com> * Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -736,7 +733,7 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, sysfs_attr_init(&dev->attr.attr); dev->attr.attr.name = dev->attr_name; dev->attr.attr.mode = 0444; - dev->attr.show = thermal_cooling_device_trip_point_show; + dev->attr.show = trip_point_show; result = device_create_file(&tz->device, &dev->attr); if (result) goto remove_symbol_link; @@ -745,8 +742,8 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, sysfs_attr_init(&dev->weight_attr.attr); dev->weight_attr.attr.name = dev->weight_attr_name; dev->weight_attr.attr.mode = S_IWUSR | S_IRUGO; - dev->weight_attr.show = thermal_cooling_device_weight_show; - dev->weight_attr.store = thermal_cooling_device_weight_store; + dev->weight_attr.show = weight_show; + dev->weight_attr.store = weight_store; result = device_create_file(&tz->device, &dev->weight_attr); if (result) goto remove_trip_file; diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h index 5e4150261500..0df190ed82a7 100644 --- a/drivers/thermal/thermal_core.h +++ b/drivers/thermal/thermal_core.h @@ -1,24 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * thermal_core.h * * Copyright (C) 2012 Intel Corp * Author: Durgadoss R <durgadoss.r@intel.com> - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ #ifndef __THERMAL_CORE_H__ @@ -75,15 +60,10 @@ void thermal_zone_destroy_device_groups(struct thermal_zone_device *); void thermal_cooling_device_setup_sysfs(struct thermal_cooling_device *); void thermal_cooling_device_destroy_sysfs(struct thermal_cooling_device *cdev); /* used only at binding time */ -ssize_t -thermal_cooling_device_trip_point_show(struct device *, - struct device_attribute *, char *); -ssize_t thermal_cooling_device_weight_show(struct device *, - struct device_attribute *, char *); - -ssize_t thermal_cooling_device_weight_store(struct device *, - struct device_attribute *, - const char *, size_t); +ssize_t trip_point_show(struct device *, struct device_attribute *, char *); +ssize_t weight_show(struct device *, struct device_attribute *, char *); +ssize_t weight_store(struct device *, struct device_attribute *, const char *, + size_t); #ifdef CONFIG_THERMAL_STATISTICS void thermal_cooling_device_stats_update(struct thermal_cooling_device *cdev, diff --git a/drivers/thermal/thermal_helpers.c b/drivers/thermal/thermal_helpers.c index eb03d7e099bb..2ba756af76b7 100644 --- a/drivers/thermal/thermal_helpers.c +++ b/drivers/thermal/thermal_helpers.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * thermal_helpers.c - helper functions to handle thermal devices * @@ -7,10 +8,6 @@ * Copyright (C) 2008 Intel Corp * Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com> * Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/thermal/thermal_hwmon.c b/drivers/thermal/thermal_hwmon.c index c4a508a124dc..11278836ed12 100644 --- a/drivers/thermal/thermal_hwmon.c +++ b/drivers/thermal/thermal_hwmon.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * thermal_hwmon.c - Generic Thermal Management hwmon support. * @@ -8,22 +9,6 @@ * * Copyright (C) 2013 Texas Instruments * Copyright (C) 2013 Eduardo Valentin <eduardo.valentin@ti.com> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ #include <linux/hwmon.h> #include <linux/thermal.h> diff --git a/drivers/thermal/thermal_hwmon.h b/drivers/thermal/thermal_hwmon.h index c798fdb2ae43..019f6f88224e 100644 --- a/drivers/thermal/thermal_hwmon.h +++ b/drivers/thermal/thermal_hwmon.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * thermal_hwmon.h - Generic Thermal Management hwmon support. * @@ -8,22 +9,6 @@ * * Copyright (C) 2013 Texas Instruments * Copyright (C) 2013 Eduardo Valentin <eduardo.valentin@ti.com> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ #ifndef __THERMAL_HWMON_H__ #define __THERMAL_HWMON_H__ diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c index 23b5e0a709b0..2241ceae7d7f 100644 --- a/drivers/thermal/thermal_sysfs.c +++ b/drivers/thermal/thermal_sysfs.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * thermal.c - sysfs interface of thermal devices * @@ -7,10 +8,6 @@ * Copyright (C) 2008 Intel Corp * Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com> * Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -381,7 +378,7 @@ sustainable_power_store(struct device *dev, struct device_attribute *devattr, \ return count; \ } \ - static DEVICE_ATTR(name, S_IWUSR | S_IRUGO, name##_show, name##_store) + static DEVICE_ATTR_RW(name) create_s32_tzp_attr(k_po); create_s32_tzp_attr(k_pu); @@ -668,17 +665,15 @@ void thermal_zone_destroy_device_groups(struct thermal_zone_device *tz) /* sys I/F for cooling device */ static ssize_t -thermal_cooling_device_type_show(struct device *dev, - struct device_attribute *attr, char *buf) +cdev_type_show(struct device *dev, struct device_attribute *attr, char *buf) { struct thermal_cooling_device *cdev = to_cooling_device(dev); return sprintf(buf, "%s\n", cdev->type); } -static ssize_t -thermal_cooling_device_max_state_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t max_state_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct thermal_cooling_device *cdev = to_cooling_device(dev); unsigned long state; @@ -690,9 +685,8 @@ thermal_cooling_device_max_state_show(struct device *dev, return sprintf(buf, "%ld\n", state); } -static ssize_t -thermal_cooling_device_cur_state_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t cur_state_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct thermal_cooling_device *cdev = to_cooling_device(dev); unsigned long state; @@ -705,9 +699,8 @@ thermal_cooling_device_cur_state_show(struct device *dev, } static ssize_t -thermal_cooling_device_cur_state_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +cur_state_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct thermal_cooling_device *cdev = to_cooling_device(dev); unsigned long state; @@ -726,13 +719,10 @@ thermal_cooling_device_cur_state_store(struct device *dev, return count; } -static struct device_attribute dev_attr_cdev_type = -__ATTR(type, 0444, thermal_cooling_device_type_show, NULL); -static DEVICE_ATTR(max_state, 0444, - thermal_cooling_device_max_state_show, NULL); -static DEVICE_ATTR(cur_state, 0644, - thermal_cooling_device_cur_state_show, - thermal_cooling_device_cur_state_store); +static struct device_attribute +dev_attr_cdev_type = __ATTR(type, 0444, cdev_type_show, NULL); +static DEVICE_ATTR_RO(max_state); +static DEVICE_ATTR_RW(cur_state); static struct attribute *cooling_device_attrs[] = { &dev_attr_cdev_type.attr, @@ -791,10 +781,8 @@ unlock: spin_unlock(&stats->lock); } -static ssize_t -thermal_cooling_device_total_trans_show(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t total_trans_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct thermal_cooling_device *cdev = to_cooling_device(dev); struct cooling_dev_stats *stats = cdev->stats; @@ -808,9 +796,8 @@ thermal_cooling_device_total_trans_show(struct device *dev, } static ssize_t -thermal_cooling_device_time_in_state_show(struct device *dev, - struct device_attribute *attr, - char *buf) +time_in_state_ms_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct thermal_cooling_device *cdev = to_cooling_device(dev); struct cooling_dev_stats *stats = cdev->stats; @@ -830,9 +817,8 @@ thermal_cooling_device_time_in_state_show(struct device *dev, } static ssize_t -thermal_cooling_device_reset_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +reset_store(struct device *dev, struct device_attribute *attr, const char *buf, + size_t count) { struct thermal_cooling_device *cdev = to_cooling_device(dev); struct cooling_dev_stats *stats = cdev->stats; @@ -853,10 +839,8 @@ thermal_cooling_device_reset_store(struct device *dev, return count; } -static ssize_t -thermal_cooling_device_trans_table_show(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t trans_table_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct thermal_cooling_device *cdev = to_cooling_device(dev); struct cooling_dev_stats *stats = cdev->stats; @@ -899,13 +883,10 @@ thermal_cooling_device_trans_table_show(struct device *dev, return len; } -static DEVICE_ATTR(total_trans, 0444, thermal_cooling_device_total_trans_show, - NULL); -static DEVICE_ATTR(time_in_state_ms, 0444, - thermal_cooling_device_time_in_state_show, NULL); -static DEVICE_ATTR(reset, 0200, NULL, thermal_cooling_device_reset_store); -static DEVICE_ATTR(trans_table, 0444, - thermal_cooling_device_trans_table_show, NULL); +static DEVICE_ATTR_RO(total_trans); +static DEVICE_ATTR_RO(time_in_state_ms); +static DEVICE_ATTR_WO(reset); +static DEVICE_ATTR_RO(trans_table); static struct attribute *cooling_device_stats_attrs[] = { &dev_attr_total_trans.attr, @@ -980,8 +961,7 @@ void thermal_cooling_device_destroy_sysfs(struct thermal_cooling_device *cdev) /* these helper will be used only at the time of bindig */ ssize_t -thermal_cooling_device_trip_point_show(struct device *dev, - struct device_attribute *attr, char *buf) +trip_point_show(struct device *dev, struct device_attribute *attr, char *buf) { struct thermal_instance *instance; @@ -995,8 +975,7 @@ thermal_cooling_device_trip_point_show(struct device *dev, } ssize_t -thermal_cooling_device_weight_show(struct device *dev, - struct device_attribute *attr, char *buf) +weight_show(struct device *dev, struct device_attribute *attr, char *buf) { struct thermal_instance *instance; @@ -1005,10 +984,8 @@ thermal_cooling_device_weight_show(struct device *dev, return sprintf(buf, "%d\n", instance->weight); } -ssize_t -thermal_cooling_device_weight_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +ssize_t weight_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct thermal_instance *instance; int ret, weight; diff --git a/drivers/thermal/ti-soc-thermal/omap5-thermal-data.c b/drivers/thermal/ti-soc-thermal/omap5-thermal-data.c index cd9a304fb571..6ac037098b52 100644 --- a/drivers/thermal/ti-soc-thermal/omap5-thermal-data.c +++ b/drivers/thermal/ti-soc-thermal/omap5-thermal-data.c @@ -310,7 +310,7 @@ omap5430_adc_to_temp[ 119800, 120200, 120600, 121000, 121400, 121800, 122400, 122600, 123000, 123400, /* Index 940 - 945 */ - 123800, 1242000, 124600, 124900, 125000, 125000, + 123800, 124200, 124600, 124900, 125000, 125000, }; /* OMAP54xx ES2.0 data */ diff --git a/drivers/thermal/uniphier_thermal.c b/drivers/thermal/uniphier_thermal.c index 95704732f760..55477d74d591 100644 --- a/drivers/thermal/uniphier_thermal.c +++ b/drivers/thermal/uniphier_thermal.c @@ -365,6 +365,10 @@ static const struct of_device_id uniphier_tm_dt_ids[] = { .compatible = "socionext,uniphier-ld20-thermal", .data = &uniphier_ld20_tm_data, }, + { + .compatible = "socionext,uniphier-pxs3-thermal", + .data = &uniphier_ld20_tm_data, + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, uniphier_tm_dt_ids); diff --git a/drivers/thermal/x86_pkg_temp_thermal.c b/drivers/thermal/x86_pkg_temp_thermal.c index 1a6c88b10a39..1ef937d799e4 100644 --- a/drivers/thermal/x86_pkg_temp_thermal.c +++ b/drivers/thermal/x86_pkg_temp_thermal.c @@ -516,7 +516,8 @@ static int __init pkg_temp_thermal_init(void) return -ENODEV; max_packages = topology_max_packages(); - packages = kzalloc(max_packages * sizeof(struct pkg_device *), GFP_KERNEL); + packages = kcalloc(max_packages, sizeof(struct pkg_device *), + GFP_KERNEL); if (!packages) return -ENOMEM; diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c index 47ac56817c43..eea4049b5dcc 100644 --- a/drivers/tty/ehv_bytechan.c +++ b/drivers/tty/ehv_bytechan.c @@ -754,7 +754,7 @@ static int __init ehv_bc_init(void) * array, then you can use pointer math (e.g. "bc - bcs") to get its * tty index. */ - bcs = kzalloc(count * sizeof(struct ehv_bc_data), GFP_KERNEL); + bcs = kcalloc(count, sizeof(struct ehv_bc_data), GFP_KERNEL); if (!bcs) return -ENOMEM; diff --git a/drivers/tty/goldfish.c b/drivers/tty/goldfish.c index 1c1bd0afcd48..37caba7c3aff 100644 --- a/drivers/tty/goldfish.c +++ b/drivers/tty/goldfish.c @@ -245,8 +245,9 @@ static int goldfish_tty_create_driver(void) int ret; struct tty_driver *tty; - goldfish_ttys = kzalloc(sizeof(*goldfish_ttys) * - goldfish_tty_line_count, GFP_KERNEL); + goldfish_ttys = kcalloc(goldfish_tty_line_count, + sizeof(*goldfish_ttys), + GFP_KERNEL); if (goldfish_ttys == NULL) { ret = -ENOMEM; goto err_alloc_goldfish_ttys_failed; diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c index a74680729825..2af1e5751bd6 100644 --- a/drivers/tty/hvc/hvc_iucv.c +++ b/drivers/tty/hvc/hvc_iucv.c @@ -1252,7 +1252,7 @@ static int hvc_iucv_setup_filter(const char *val) if (size > MAX_VMID_FILTER) return -ENOSPC; - array = kzalloc(size * 8, GFP_KERNEL); + array = kcalloc(size, 8, GFP_KERNEL); if (!array) return -ENOMEM; diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index 1db1d97e72e7..cb4db1b3ca3c 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c @@ -1441,7 +1441,8 @@ static int hvcs_alloc_index_list(int n) { int i; - hvcs_index_list = kmalloc(n * sizeof(hvcs_index_count),GFP_KERNEL); + hvcs_index_list = kmalloc_array(n, sizeof(hvcs_index_count), + GFP_KERNEL); if (!hvcs_index_list) return -ENOMEM; hvcs_index_count = n; diff --git a/drivers/tty/isicom.c b/drivers/tty/isicom.c index bdd3027ef01b..8d96e86966f1 100644 --- a/drivers/tty/isicom.c +++ b/drivers/tty/isicom.c @@ -1477,7 +1477,7 @@ static int load_firmware(struct pci_dev *pdev, goto errrelfw; } - data = kmalloc(word_count * 2, GFP_KERNEL); + data = kmalloc_array(word_count, 2, GFP_KERNEL); if (data == NULL) { dev_err(&pdev->dev, "Card%d, firmware upload " "failed, not enough memory\n", index + 1); diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 55b3eff148b1..8e4428725848 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -2738,8 +2738,9 @@ static int atmel_serial_probe(struct platform_device *pdev) if (!atmel_use_pdc_rx(&atmel_port->uart)) { ret = -ENOMEM; - data = kmalloc(sizeof(struct atmel_uart_char) - * ATMEL_SERIAL_RINGSIZE, GFP_KERNEL); + data = kmalloc_array(ATMEL_SERIAL_RINGSIZE, + sizeof(struct atmel_uart_char), + GFP_KERNEL); if (!data) goto err_alloc_ring; atmel_port->rx_ring.buf = data; diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 760d5dd0aada..cb85002a10d8 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -991,7 +991,7 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv) priv->tx_dma_use = 1; - priv->sg_tx_p = kzalloc(sizeof(struct scatterlist)*num, GFP_ATOMIC); + priv->sg_tx_p = kcalloc(num, sizeof(struct scatterlist), GFP_ATOMIC); if (!priv->sg_tx_p) { dev_err(priv->port.dev, "%s:kzalloc Failed\n", __func__); return 0; diff --git a/drivers/tty/serial/rp2.c b/drivers/tty/serial/rp2.c index 520b43b23543..5690c09cc041 100644 --- a/drivers/tty/serial/rp2.c +++ b/drivers/tty/serial/rp2.c @@ -774,7 +774,7 @@ static int rp2_probe(struct pci_dev *pdev, rp2_init_card(card); - ports = devm_kzalloc(&pdev->dev, sizeof(*ports) * card->n_ports, + ports = devm_kcalloc(&pdev->dev, card->n_ports, sizeof(*ports), GFP_KERNEL); if (!ports) return -ENOMEM; diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 890b8832aff2..9c14a453f73c 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -2445,7 +2445,7 @@ int uart_register_driver(struct uart_driver *drv) * Maybe we should be using a slab cache for this, especially if * we have a large number of ports to handle. */ - drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL); + drv->state = kcalloc(drv->nr, sizeof(struct uart_state), GFP_KERNEL); if (!drv->state) goto out; diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c index b93d0225f8c9..72131b5e132e 100644 --- a/drivers/tty/serial/sunsab.c +++ b/drivers/tty/serial/sunsab.c @@ -1125,8 +1125,9 @@ static int __init sunsab_init(void) } if (num_channels) { - sunsab_ports = kzalloc(sizeof(struct uart_sunsab_port) * - num_channels, GFP_KERNEL); + sunsab_ports = kcalloc(num_channels, + sizeof(struct uart_sunsab_port), + GFP_KERNEL); if (!sunsab_ports) return -ENOMEM; diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 7c838b90a31d..aba59521ad48 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -867,8 +867,13 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count, i = -EIO; tty_ldisc_deref(ld); - if (i > 0) - tty_update_time(&inode->i_atime); + if (i > 0) { + struct timespec ts; + + ts = timespec64_to_timespec(inode->i_atime); + tty_update_time(&ts); + inode->i_atime = timespec_to_timespec64(ts); + } return i; } @@ -969,7 +974,11 @@ static inline ssize_t do_tty_write( cond_resched(); } if (written) { - tty_update_time(&file_inode(file)->i_mtime); + struct timespec ts; + + ts = timespec64_to_timespec(file_inode(file)->i_mtime); + tty_update_time(&ts); + file_inode(file)->i_mtime = timespec_to_timespec64(ts); ret = written; } out: diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 722a6690c70d..7c7ada0b3ea0 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -231,7 +231,7 @@ static void set_inverse_trans_unicode(struct vc_data *conp, q = p->inverse_trans_unicode; if (!q) { q = p->inverse_trans_unicode = - kmalloc(MAX_GLYPH * sizeof(u16), GFP_KERNEL); + kmalloc_array(MAX_GLYPH, sizeof(u16), GFP_KERNEL); if (!q) return; } @@ -479,7 +479,8 @@ con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos) p1 = p->uni_pgdir[n = unicode >> 11]; if (!p1) { - p1 = p->uni_pgdir[n] = kmalloc(32*sizeof(u16 *), GFP_KERNEL); + p1 = p->uni_pgdir[n] = kmalloc_array(32, sizeof(u16 *), + GFP_KERNEL); if (!p1) return -ENOMEM; for (i = 0; i < 32; i++) p1[i] = NULL; @@ -487,7 +488,7 @@ con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos) p2 = p1[n = (unicode >> 6) & 0x1f]; if (!p2) { - p2 = p1[n] = kmalloc(64*sizeof(u16), GFP_KERNEL); + p2 = p1[n] = kmalloc_array(64, sizeof(u16), GFP_KERNEL); if (!p2) return -ENOMEM; memset(p2, 0xff, 64*sizeof(u16)); /* No glyphs for the characters (yet) */ } diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 5d412df8e943..d5b4a2b44ab8 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -1624,7 +1624,7 @@ int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm) struct kbdiacr *dia; int i; - dia = kmalloc(MAX_DIACR * sizeof(struct kbdiacr), + dia = kmalloc_array(MAX_DIACR, sizeof(struct kbdiacr), GFP_KERNEL); if (!dia) return -ENOMEM; @@ -1657,7 +1657,7 @@ int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm) struct kbdiacrsuc __user *a = udp; void *buf; - buf = kmalloc(MAX_DIACR * sizeof(struct kbdiacruc), + buf = kmalloc_array(MAX_DIACR, sizeof(struct kbdiacruc), GFP_KERNEL); if (buf == NULL) return -ENOMEM; diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index 7851383fbd6c..90ea1cc52b7a 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -280,7 +280,8 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t /* Allocate a new buffer before freeing the old one ... */ multiplier = use_unicode ? 3 : 1; /* chars can take up to 3 bytes */ - bp = kmalloc(((sel_end-sel_start)/2+1)*multiplier, GFP_KERNEL); + bp = kmalloc_array((sel_end - sel_start) / 2 + 1, multiplier, + GFP_KERNEL); if (!bp) { printk(KERN_WARNING "selection: kmalloc() failed\n"); clear_selection(); diff --git a/drivers/uio/uio_pruss.c b/drivers/uio/uio_pruss.c index 31d5b1d3b5af..91aea8823af5 100644 --- a/drivers/uio/uio_pruss.c +++ b/drivers/uio/uio_pruss.c @@ -129,7 +129,7 @@ static int pruss_probe(struct platform_device *pdev) if (!gdev) return -ENOMEM; - gdev->info = kzalloc(sizeof(*p) * MAX_PRUSS_EVT, GFP_KERNEL); + gdev->info = kcalloc(MAX_PRUSS_EVT, sizeof(*p), GFP_KERNEL); if (!gdev->info) { kfree(gdev); return -ENOMEM; diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 76e16c5251b9..476dcc5f2da3 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -897,7 +897,7 @@ static int parse_usbdevfs_streams(struct usb_dev_state *ps, if (num_streams_ret && (num_streams < 2 || num_streams > 65536)) return -EINVAL; - eps = kmalloc(num_eps * sizeof(*eps), GFP_KERNEL); + eps = kmalloc_array(num_eps, sizeof(*eps), GFP_KERNEL); if (!eps) return -ENOMEM; @@ -1602,8 +1602,9 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb as->mem_usage = u; if (num_sgs) { - as->urb->sg = kmalloc(num_sgs * sizeof(struct scatterlist), - GFP_KERNEL); + as->urb->sg = kmalloc_array(num_sgs, + sizeof(struct scatterlist), + GFP_KERNEL); if (!as->urb->sg) { ret = -ENOMEM; goto error; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 26c2438d2889..fcae521df29b 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1376,7 +1376,7 @@ static int hub_configure(struct usb_hub *hub, dev_info(hub_dev, "%d port%s detected\n", maxchild, (maxchild == 1) ? "" : "s"); - hub->ports = kzalloc(maxchild * sizeof(struct usb_port *), GFP_KERNEL); + hub->ports = kcalloc(maxchild, sizeof(struct usb_port *), GFP_KERNEL); if (!hub->ports) { ret = -ENOMEM; goto fail; diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 7b137003c2be..1a15392326fc 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -390,7 +390,7 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev, } /* initialize all the urbs we'll use */ - io->urbs = kmalloc(io->entries * sizeof(*io->urbs), mem_flags); + io->urbs = kmalloc_array(io->entries, sizeof(*io->urbs), mem_flags); if (!io->urbs) goto nomem; @@ -1824,8 +1824,8 @@ int usb_set_configuration(struct usb_device *dev, int configuration) n = nintf = 0; if (cp) { nintf = cp->desc.bNumInterfaces; - new_interfaces = kmalloc(nintf * sizeof(*new_interfaces), - GFP_NOIO); + new_interfaces = kmalloc_array(nintf, sizeof(*new_interfaces), + GFP_NOIO); if (!new_interfaces) return -ENOMEM; diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 1faefea16cec..edaf0b6af4f0 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -5079,13 +5079,14 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg) dev_dbg(hsotg->dev, "hcfg=%08x\n", hcfg); #ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS - hsotg->frame_num_array = kzalloc(sizeof(*hsotg->frame_num_array) * - FRAME_NUM_ARRAY_SIZE, GFP_KERNEL); + hsotg->frame_num_array = kcalloc(FRAME_NUM_ARRAY_SIZE, + sizeof(*hsotg->frame_num_array), + GFP_KERNEL); if (!hsotg->frame_num_array) goto error1; - hsotg->last_frame_num_array = kzalloc( - sizeof(*hsotg->last_frame_num_array) * - FRAME_NUM_ARRAY_SIZE, GFP_KERNEL); + hsotg->last_frame_num_array = + kcalloc(FRAME_NUM_ARRAY_SIZE, + sizeof(*hsotg->last_frame_num_array), GFP_KERNEL); if (!hsotg->last_frame_num_array) goto error1; #endif diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 199d25700050..dce9d12c7981 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -1308,7 +1308,7 @@ ffs_sb_make_inode(struct super_block *sb, void *data, inode = new_inode(sb); if (likely(inode)) { - struct timespec ts = current_time(inode); + struct timespec64 ts = current_time(inode); inode->i_ino = get_next_ino(); inode->i_mode = perms->mode; diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c index a4d99bf50f2f..17147b8c771e 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.c +++ b/drivers/usb/gadget/udc/atmel_usba_udc.c @@ -2036,7 +2036,7 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev, udc->num_ep = usba_config_fifo_table(udc); } - eps = devm_kzalloc(&pdev->dev, sizeof(struct usba_ep) * udc->num_ep, + eps = devm_kcalloc(&pdev->dev, udc->num_ep, sizeof(struct usba_ep), GFP_KERNEL); if (!eps) return ERR_PTR(-ENOMEM); diff --git a/drivers/usb/gadget/udc/bdc/bdc_ep.c b/drivers/usb/gadget/udc/bdc/bdc_ep.c index 03149b9d7ea7..a4d9b5e1e50e 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_ep.c +++ b/drivers/usb/gadget/udc/bdc/bdc_ep.c @@ -138,9 +138,9 @@ static int ep_bd_list_alloc(struct bdc_ep *ep) __func__, ep, num_tabs); /* Allocate memory for table array */ - ep->bd_list.bd_table_array = kzalloc( - num_tabs * sizeof(struct bd_table *), - GFP_ATOMIC); + ep->bd_list.bd_table_array = kcalloc(num_tabs, + sizeof(struct bd_table *), + GFP_ATOMIC); if (!ep->bd_list.bd_table_array) return -ENOMEM; diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c index 9a3f7db26a5e..be59309e848c 100644 --- a/drivers/usb/gadget/udc/fsl_udc_core.c +++ b/drivers/usb/gadget/udc/fsl_udc_core.c @@ -2246,7 +2246,7 @@ static int struct_udc_setup(struct fsl_udc *udc, pdata = dev_get_platdata(&pdev->dev); udc->phy_mode = pdata->phy_mode; - udc->eps = kzalloc(sizeof(struct fsl_ep) * udc->max_ep, GFP_KERNEL); + udc->eps = kcalloc(udc->max_ep, sizeof(struct fsl_ep), GFP_KERNEL); if (!udc->eps) return -1; diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c index 977ea1a02cf9..7cf98c793e04 100644 --- a/drivers/usb/gadget/udc/renesas_usb3.c +++ b/drivers/usb/gadget/udc/renesas_usb3.c @@ -2427,7 +2427,8 @@ static int renesas_usb3_init_ep(struct renesas_usb3 *usb3, struct device *dev, if (usb3->num_usb3_eps > USB3_MAX_NUM_PIPES) usb3->num_usb3_eps = USB3_MAX_NUM_PIPES; - usb3->usb3_ep = devm_kzalloc(dev, sizeof(*usb3_ep) * usb3->num_usb3_eps, + usb3->usb3_ep = devm_kcalloc(dev, + usb3->num_usb3_eps, sizeof(*usb3_ep), GFP_KERNEL); if (!usb3->usb3_ep) return -ENOMEM; diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index e56db44708bc..1d87295682b8 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -117,8 +117,9 @@ static struct ehci_tt *find_tt(struct usb_device *udev) if (utt->multi) { tt_index = utt->hcpriv; if (!tt_index) { /* Create the index array */ - tt_index = kzalloc(utt->hub->maxchild * - sizeof(*tt_index), GFP_ATOMIC); + tt_index = kcalloc(utt->hub->maxchild, + sizeof(*tt_index), + GFP_ATOMIC); if (!tt_index) return ERR_PTR(-ENOMEM); utt->hcpriv = tt_index; diff --git a/drivers/usb/host/fhci-tds.c b/drivers/usb/host/fhci-tds.c index 3a4e8f616751..f3308ce25043 100644 --- a/drivers/usb/host/fhci-tds.c +++ b/drivers/usb/host/fhci-tds.c @@ -189,7 +189,7 @@ u32 fhci_create_ep(struct fhci_usb *usb, enum fhci_mem_alloc data_mem, goto err; } - buff = kmalloc(1028 * sizeof(*buff), GFP_KERNEL); + buff = kmalloc_array(1028, sizeof(*buff), GFP_KERNEL); if (!buff) { kfree(pkt); err_for = "buffer"; diff --git a/drivers/usb/host/imx21-hcd.c b/drivers/usb/host/imx21-hcd.c index 3a8bbfe43a8e..6e3dad19d369 100644 --- a/drivers/usb/host/imx21-hcd.c +++ b/drivers/usb/host/imx21-hcd.c @@ -741,8 +741,8 @@ static int imx21_hc_urb_enqueue_isoc(struct usb_hcd *hcd, if (urb_priv == NULL) return -ENOMEM; - urb_priv->isoc_td = kzalloc( - sizeof(struct td) * urb->number_of_packets, mem_flags); + urb_priv->isoc_td = kcalloc(urb->number_of_packets, sizeof(struct td), + mem_flags); if (urb_priv->isoc_td == NULL) { ret = -ENOMEM; goto alloc_td_failed; diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c index d3ee1f52aaab..4f267dc93882 100644 --- a/drivers/usb/host/ohci-dbg.c +++ b/drivers/usb/host/ohci-dbg.c @@ -492,7 +492,7 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf) char *next; unsigned i; - seen = kmalloc(DBG_SCHED_LIMIT * sizeof *seen, GFP_ATOMIC); + seen = kmalloc_array(DBG_SCHED_LIMIT, sizeof(*seen), GFP_ATOMIC); if (!seen) return 0; seen_count = 0; diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 4fe74711938e..acbd3d7b8828 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -2274,8 +2274,8 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags) xhci->hw_ports[i].hw_portnum = i; } - xhci->rh_bw = kzalloc_node(sizeof(*xhci->rh_bw)*num_ports, flags, - dev_to_node(dev)); + xhci->rh_bw = kcalloc_node(num_ports, sizeof(*xhci->rh_bw), flags, + dev_to_node(dev)); if (!xhci->rh_bw) return -ENOMEM; for (i = 0; i < num_ports; i++) { diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c index 236a60f53099..c2e255f02a72 100644 --- a/drivers/usb/misc/ldusb.c +++ b/drivers/usb/misc/ldusb.c @@ -695,7 +695,10 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id * dev_warn(&intf->dev, "Interrupt out endpoint not found (using control endpoint instead)\n"); dev->interrupt_in_endpoint_size = usb_endpoint_maxp(dev->interrupt_in_endpoint); - dev->ring_buffer = kmalloc(ring_buffer_size*(sizeof(size_t)+dev->interrupt_in_endpoint_size), GFP_KERNEL); + dev->ring_buffer = + kmalloc_array(ring_buffer_size, + sizeof(size_t) + dev->interrupt_in_endpoint_size, + GFP_KERNEL); if (!dev->ring_buffer) goto error; dev->interrupt_in_buffer = kmalloc(dev->interrupt_in_endpoint_size, GFP_KERNEL); @@ -706,7 +709,9 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id * goto error; dev->interrupt_out_endpoint_size = dev->interrupt_out_endpoint ? usb_endpoint_maxp(dev->interrupt_out_endpoint) : udev->descriptor.bMaxPacketSize0; - dev->interrupt_out_buffer = kmalloc(write_buffer_size*dev->interrupt_out_endpoint_size, GFP_KERNEL); + dev->interrupt_out_buffer = + kmalloc_array(write_buffer_size, + dev->interrupt_out_endpoint_size, GFP_KERNEL); if (!dev->interrupt_out_buffer) goto error; dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL); diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index a0d6e0af957c..c4f017e1d17a 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -1243,7 +1243,7 @@ sisusbcon_font_set(struct vc_data *c, struct console_font *font, } if (!sisusb->font_backup) - sisusb->font_backup = vmalloc(charcount * 32); + sisusb->font_backup = vmalloc(array_size(charcount, 32)); if (sisusb->font_backup) { memcpy(sisusb->font_backup, font->data, charcount * 32); diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c index 34e866ad4a81..ad2c082bd0fb 100644 --- a/drivers/usb/mon/mon_bin.c +++ b/drivers/usb/mon/mon_bin.c @@ -1024,7 +1024,8 @@ static long mon_bin_ioctl(struct file *file, unsigned int cmd, unsigned long arg return -EINVAL; size = CHUNK_ALIGN(arg); - vec = kzalloc(sizeof(struct mon_pgmap) * (size / CHUNK_SIZE), GFP_KERNEL); + vec = kcalloc(size / CHUNK_SIZE, sizeof(struct mon_pgmap), + GFP_KERNEL); if (vec == NULL) { ret = -ENOMEM; break; diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 34ee9ebe12a3..33d059c40616 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -1068,7 +1068,7 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv) if (!gpriv) return -ENOMEM; - uep = kzalloc(sizeof(struct usbhsg_uep) * pipe_size, GFP_KERNEL); + uep = kcalloc(pipe_size, sizeof(struct usbhsg_uep), GFP_KERNEL); if (!uep) { ret = -ENOMEM; goto usbhs_mod_gadget_probe_err_gpriv; diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c index 9677e0e31475..c4922b96c93b 100644 --- a/drivers/usb/renesas_usbhs/pipe.c +++ b/drivers/usb/renesas_usbhs/pipe.c @@ -803,7 +803,8 @@ int usbhs_pipe_probe(struct usbhs_priv *priv) return -EINVAL; } - info->pipe = kzalloc(sizeof(struct usbhs_pipe) * pipe_size, GFP_KERNEL); + info->pipe = kcalloc(pipe_size, sizeof(struct usbhs_pipe), + GFP_KERNEL); if (!info->pipe) return -ENOMEM; diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c index 62c91e360baf..2fb71303ec3a 100644 --- a/drivers/usb/serial/iuu_phoenix.c +++ b/drivers/usb/serial/iuu_phoenix.c @@ -736,7 +736,7 @@ static int iuu_uart_on(struct usb_serial_port *port) int status; u8 *buf; - buf = kmalloc(sizeof(u8) * 4, GFP_KERNEL); + buf = kmalloc(4, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -790,7 +790,7 @@ static int iuu_uart_baud(struct usb_serial_port *port, u32 baud_base, unsigned int T1FrekvensHZ = 0; dev_dbg(&port->dev, "%s - enter baud_base=%d\n", __func__, baud_base); - dataout = kmalloc(sizeof(u8) * 5, GFP_KERNEL); + dataout = kmalloc(5, GFP_KERNEL); if (!dataout) return -ENOMEM; diff --git a/drivers/usb/storage/alauda.c b/drivers/usb/storage/alauda.c index 900591df8bb2..6b8edf6178df 100644 --- a/drivers/usb/storage/alauda.c +++ b/drivers/usb/storage/alauda.c @@ -1025,7 +1025,7 @@ static int alauda_write_data(struct us_data *us, unsigned long address, * We also need a temporary block buffer, where we read in the old data, * overwrite parts with the new data, and manipulate the redundancy data */ - blockbuffer = kmalloc((pagesize + 64) * blocksize, GFP_NOIO); + blockbuffer = kmalloc_array(pagesize + 64, blocksize, GFP_NOIO); if (!blockbuffer) { kfree(buffer); return USB_STOR_TRANSPORT_ERROR; diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c index 93cf57ac47d6..4d261e4de9ad 100644 --- a/drivers/usb/storage/ene_ub6250.c +++ b/drivers/usb/storage/ene_ub6250.c @@ -807,8 +807,12 @@ static int ms_lib_alloc_logicalmap(struct us_data *us) u32 i; struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - info->MS_Lib.Phy2LogMap = kmalloc(info->MS_Lib.NumberOfPhyBlock * sizeof(u16), GFP_KERNEL); - info->MS_Lib.Log2PhyMap = kmalloc(info->MS_Lib.NumberOfLogBlock * sizeof(u16), GFP_KERNEL); + info->MS_Lib.Phy2LogMap = kmalloc_array(info->MS_Lib.NumberOfPhyBlock, + sizeof(u16), + GFP_KERNEL); + info->MS_Lib.Log2PhyMap = kmalloc_array(info->MS_Lib.NumberOfLogBlock, + sizeof(u16), + GFP_KERNEL); if ((info->MS_Lib.Phy2LogMap == NULL) || (info->MS_Lib.Log2PhyMap == NULL)) { ms_lib_free_logicalmap(us); @@ -1113,8 +1117,12 @@ static int ms_lib_alloc_writebuf(struct us_data *us) info->MS_Lib.wrtblk = (u16)-1; - info->MS_Lib.blkpag = kmalloc(info->MS_Lib.PagesPerBlock * info->MS_Lib.BytesPerSector, GFP_KERNEL); - info->MS_Lib.blkext = kmalloc(info->MS_Lib.PagesPerBlock * sizeof(struct ms_lib_type_extdat), GFP_KERNEL); + info->MS_Lib.blkpag = kmalloc_array(info->MS_Lib.PagesPerBlock, + info->MS_Lib.BytesPerSector, + GFP_KERNEL); + info->MS_Lib.blkext = kmalloc_array(info->MS_Lib.PagesPerBlock, + sizeof(struct ms_lib_type_extdat), + GFP_KERNEL); if ((info->MS_Lib.blkpag == NULL) || (info->MS_Lib.blkext == NULL)) { ms_lib_free_writebuf(us); diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c index 1cf7dbfe277c..bc9da736bdfc 100644 --- a/drivers/usb/storage/sddr09.c +++ b/drivers/usb/storage/sddr09.c @@ -1231,8 +1231,8 @@ sddr09_read_map(struct us_data *us) { kfree(info->lba_to_pba); kfree(info->pba_to_lba); - info->lba_to_pba = kmalloc(numblocks*sizeof(int), GFP_NOIO); - info->pba_to_lba = kmalloc(numblocks*sizeof(int), GFP_NOIO); + info->lba_to_pba = kmalloc_array(numblocks, sizeof(int), GFP_NOIO); + info->pba_to_lba = kmalloc_array(numblocks, sizeof(int), GFP_NOIO); if (info->lba_to_pba == NULL || info->pba_to_lba == NULL) { printk(KERN_WARNING "sddr09_read_map: out of memory\n"); diff --git a/drivers/usb/storage/sddr55.c b/drivers/usb/storage/sddr55.c index 8c814b2ec9b2..b8527c55335b 100644 --- a/drivers/usb/storage/sddr55.c +++ b/drivers/usb/storage/sddr55.c @@ -651,7 +651,7 @@ static int sddr55_read_map(struct us_data *us) { numblocks = info->capacity >> (info->blockshift + info->pageshift); - buffer = kmalloc( numblocks * 2, GFP_NOIO ); + buffer = kmalloc_array(numblocks, 2, GFP_NOIO ); if (!buffer) return -1; @@ -684,8 +684,8 @@ static int sddr55_read_map(struct us_data *us) { kfree(info->lba_to_pba); kfree(info->pba_to_lba); - info->lba_to_pba = kmalloc(numblocks*sizeof(int), GFP_NOIO); - info->pba_to_lba = kmalloc(numblocks*sizeof(int), GFP_NOIO); + info->lba_to_pba = kmalloc_array(numblocks, sizeof(int), GFP_NOIO); + info->pba_to_lba = kmalloc_array(numblocks, sizeof(int), GFP_NOIO); if (info->lba_to_pba == NULL || info->pba_to_lba == NULL) { kfree(info->lba_to_pba); diff --git a/drivers/usb/wusbcore/wa-rpipe.c b/drivers/usb/wusbcore/wa-rpipe.c index d0f1a6698460..38884aac862b 100644 --- a/drivers/usb/wusbcore/wa-rpipe.c +++ b/drivers/usb/wusbcore/wa-rpipe.c @@ -470,7 +470,8 @@ error: int wa_rpipes_create(struct wahc *wa) { wa->rpipes = le16_to_cpu(wa->wa_descr->wNumRPipes); - wa->rpipe_bm = kzalloc(BITS_TO_LONGS(wa->rpipes)*sizeof(unsigned long), + wa->rpipe_bm = kcalloc(BITS_TO_LONGS(wa->rpipes), + sizeof(unsigned long), GFP_KERNEL); if (wa->rpipe_bm == NULL) return -ENOMEM; diff --git a/drivers/uwb/est.c b/drivers/uwb/est.c index f3e232584284..ad30ddfe30b3 100644 --- a/drivers/uwb/est.c +++ b/drivers/uwb/est.c @@ -217,7 +217,7 @@ static int uwb_est_grow(void) { size_t actual_size = uwb_est_size * sizeof(uwb_est[0]); - void *new = kmalloc(2 * actual_size, GFP_ATOMIC); + void *new = kmalloc_array(2, actual_size, GFP_ATOMIC); if (new == NULL) return -ENOMEM; memcpy(new, uwb_est, actual_size); diff --git a/drivers/uwb/i1480/dfu/usb.c b/drivers/uwb/i1480/dfu/usb.c index a50cf45e530f..c0430a41e24b 100644 --- a/drivers/uwb/i1480/dfu/usb.c +++ b/drivers/uwb/i1480/dfu/usb.c @@ -376,7 +376,7 @@ int i1480_usb_probe(struct usb_interface *iface, const struct usb_device_id *id) i1480 = &i1480_usb->i1480; i1480->buf_size = 512; - i1480->cmd_buf = kmalloc(2 * i1480->buf_size, GFP_KERNEL); + i1480->cmd_buf = kmalloc_array(2, i1480->buf_size, GFP_KERNEL); if (i1480->cmd_buf == NULL) { dev_err(dev, "Cannot allocate transfer buffers\n"); result = -ENOMEM; diff --git a/drivers/vfio/mdev/mdev_core.c b/drivers/vfio/mdev/mdev_core.c index 126991046eb7..0212f0ee8aea 100644 --- a/drivers/vfio/mdev/mdev_core.c +++ b/drivers/vfio/mdev/mdev_core.c @@ -66,34 +66,6 @@ uuid_le mdev_uuid(struct mdev_device *mdev) } EXPORT_SYMBOL(mdev_uuid); -static int _find_mdev_device(struct device *dev, void *data) -{ - struct mdev_device *mdev; - - if (!dev_is_mdev(dev)) - return 0; - - mdev = to_mdev_device(dev); - - if (uuid_le_cmp(mdev->uuid, *(uuid_le *)data) == 0) - return 1; - - return 0; -} - -static bool mdev_device_exist(struct mdev_parent *parent, uuid_le uuid) -{ - struct device *dev; - - dev = device_find_child(parent->dev, &uuid, _find_mdev_device); - if (dev) { - put_device(dev); - return true; - } - - return false; -} - /* Should be called holding parent_list_lock */ static struct mdev_parent *__find_parent_device(struct device *dev) { @@ -221,7 +193,6 @@ int mdev_register_device(struct device *dev, const struct mdev_parent_ops *ops) } kref_init(&parent->ref); - mutex_init(&parent->lock); parent->dev = dev; parent->ops = ops; @@ -297,6 +268,10 @@ static void mdev_device_release(struct device *dev) { struct mdev_device *mdev = to_mdev_device(dev); + mutex_lock(&mdev_list_lock); + list_del(&mdev->next); + mutex_unlock(&mdev_list_lock); + dev_dbg(&mdev->dev, "MDEV: destroying\n"); kfree(mdev); } @@ -304,7 +279,7 @@ static void mdev_device_release(struct device *dev) int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid) { int ret; - struct mdev_device *mdev; + struct mdev_device *mdev, *tmp; struct mdev_parent *parent; struct mdev_type *type = to_mdev_type(kobj); @@ -312,21 +287,28 @@ int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid) if (!parent) return -EINVAL; - mutex_lock(&parent->lock); + mutex_lock(&mdev_list_lock); /* Check for duplicate */ - if (mdev_device_exist(parent, uuid)) { - ret = -EEXIST; - goto create_err; + list_for_each_entry(tmp, &mdev_list, next) { + if (!uuid_le_cmp(tmp->uuid, uuid)) { + mutex_unlock(&mdev_list_lock); + ret = -EEXIST; + goto mdev_fail; + } } mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); if (!mdev) { + mutex_unlock(&mdev_list_lock); ret = -ENOMEM; - goto create_err; + goto mdev_fail; } memcpy(&mdev->uuid, &uuid, sizeof(uuid_le)); + list_add(&mdev->next, &mdev_list); + mutex_unlock(&mdev_list_lock); + mdev->parent = parent; kref_init(&mdev->ref); @@ -338,35 +320,28 @@ int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid) ret = device_register(&mdev->dev); if (ret) { put_device(&mdev->dev); - goto create_err; + goto mdev_fail; } ret = mdev_device_create_ops(kobj, mdev); if (ret) - goto create_failed; + goto create_fail; ret = mdev_create_sysfs_files(&mdev->dev, type); if (ret) { mdev_device_remove_ops(mdev, true); - goto create_failed; + goto create_fail; } mdev->type_kobj = kobj; + mdev->active = true; dev_dbg(&mdev->dev, "MDEV: created\n"); - mutex_unlock(&parent->lock); - - mutex_lock(&mdev_list_lock); - list_add(&mdev->next, &mdev_list); - mutex_unlock(&mdev_list_lock); - - return ret; + return 0; -create_failed: +create_fail: device_unregister(&mdev->dev); - -create_err: - mutex_unlock(&parent->lock); +mdev_fail: mdev_put_parent(parent); return ret; } @@ -377,44 +352,39 @@ int mdev_device_remove(struct device *dev, bool force_remove) struct mdev_parent *parent; struct mdev_type *type; int ret; - bool found = false; mdev = to_mdev_device(dev); mutex_lock(&mdev_list_lock); list_for_each_entry(tmp, &mdev_list, next) { - if (tmp == mdev) { - found = true; + if (tmp == mdev) break; - } } - if (found) - list_del(&mdev->next); + if (tmp != mdev) { + mutex_unlock(&mdev_list_lock); + return -ENODEV; + } - mutex_unlock(&mdev_list_lock); + if (!mdev->active) { + mutex_unlock(&mdev_list_lock); + return -EAGAIN; + } - if (!found) - return -ENODEV; + mdev->active = false; + mutex_unlock(&mdev_list_lock); type = to_mdev_type(mdev->type_kobj); parent = mdev->parent; - mutex_lock(&parent->lock); ret = mdev_device_remove_ops(mdev, force_remove); if (ret) { - mutex_unlock(&parent->lock); - - mutex_lock(&mdev_list_lock); - list_add(&mdev->next, &mdev_list); - mutex_unlock(&mdev_list_lock); - + mdev->active = true; return ret; } mdev_remove_sysfs_files(dev, type); device_unregister(dev); - mutex_unlock(&parent->lock); mdev_put_parent(parent); return 0; diff --git a/drivers/vfio/mdev/mdev_private.h b/drivers/vfio/mdev/mdev_private.h index a9cefd70a705..b5819b7d7ef7 100644 --- a/drivers/vfio/mdev/mdev_private.h +++ b/drivers/vfio/mdev/mdev_private.h @@ -20,7 +20,6 @@ struct mdev_parent { struct device *dev; const struct mdev_parent_ops *ops; struct kref ref; - struct mutex lock; struct list_head next; struct kset *mdev_types_kset; struct list_head type_list; @@ -34,6 +33,7 @@ struct mdev_device { struct kref ref; struct list_head next; struct kobject *type_kobj; + bool active; }; #define to_mdev_device(dev) container_of(dev, struct mdev_device, dev) diff --git a/drivers/vfio/mdev/mdev_sysfs.c b/drivers/vfio/mdev/mdev_sysfs.c index 802df210929b..249472f05509 100644 --- a/drivers/vfio/mdev/mdev_sysfs.c +++ b/drivers/vfio/mdev/mdev_sysfs.c @@ -257,24 +257,24 @@ int mdev_create_sysfs_files(struct device *dev, struct mdev_type *type) { int ret; - ret = sysfs_create_files(&dev->kobj, mdev_device_attrs); - if (ret) - return ret; - ret = sysfs_create_link(type->devices_kobj, &dev->kobj, dev_name(dev)); if (ret) - goto device_link_failed; + return ret; ret = sysfs_create_link(&dev->kobj, &type->kobj, "mdev_type"); if (ret) goto type_link_failed; + ret = sysfs_create_files(&dev->kobj, mdev_device_attrs); + if (ret) + goto create_files_failed; + return ret; +create_files_failed: + sysfs_remove_link(&dev->kobj, "mdev_type"); type_link_failed: sysfs_remove_link(type->devices_kobj, dev_name(dev)); -device_link_failed: - sysfs_remove_files(&dev->kobj, mdev_device_attrs); return ret; } diff --git a/drivers/vfio/platform/vfio_platform_common.c b/drivers/vfio/platform/vfio_platform_common.c index 4c27f4be3c3d..c0cd824be2b7 100644 --- a/drivers/vfio/platform/vfio_platform_common.c +++ b/drivers/vfio/platform/vfio_platform_common.c @@ -17,6 +17,7 @@ #include <linux/iommu.h> #include <linux/module.h> #include <linux/mutex.h> +#include <linux/pm_runtime.h> #include <linux/slab.h> #include <linux/types.h> #include <linux/uaccess.h> @@ -239,6 +240,7 @@ static void vfio_platform_release(void *device_data) ret, extra_dbg ? extra_dbg : ""); WARN_ON(1); } + pm_runtime_put(vdev->device); vfio_platform_regions_cleanup(vdev); vfio_platform_irq_cleanup(vdev); } @@ -269,6 +271,10 @@ static int vfio_platform_open(void *device_data) if (ret) goto err_irq; + ret = pm_runtime_get_sync(vdev->device); + if (ret < 0) + goto err_pm; + ret = vfio_platform_call_reset(vdev, &extra_dbg); if (ret && vdev->reset_required) { dev_warn(vdev->device, "reset driver is required and reset call failed in open (%d) %s\n", @@ -283,6 +289,8 @@ static int vfio_platform_open(void *device_data) return 0; err_rst: + pm_runtime_put(vdev->device); +err_pm: vfio_platform_irq_cleanup(vdev); err_irq: vfio_platform_regions_cleanup(vdev); @@ -630,8 +638,7 @@ static int vfio_platform_of_probe(struct vfio_platform_device *vdev, ret = device_property_read_string(dev, "compatible", &vdev->compat); if (ret) - pr_err("VFIO: cannot retrieve compat for %s\n", - vdev->name); + pr_err("VFIO: Cannot retrieve compat for %s\n", vdev->name); return ret; } @@ -673,7 +680,7 @@ int vfio_platform_probe_common(struct vfio_platform_device *vdev, ret = vfio_platform_get_reset(vdev); if (ret && vdev->reset_required) { - pr_err("vfio: no reset function found for device %s\n", + pr_err("VFIO: No reset function found for device %s\n", vdev->name); return ret; } @@ -681,18 +688,24 @@ int vfio_platform_probe_common(struct vfio_platform_device *vdev, group = vfio_iommu_group_get(dev); if (!group) { pr_err("VFIO: No IOMMU group for device %s\n", vdev->name); - return -EINVAL; + ret = -EINVAL; + goto put_reset; } ret = vfio_add_group_dev(dev, &vfio_platform_ops, vdev); - if (ret) { - vfio_iommu_group_put(group, dev); - return ret; - } + if (ret) + goto put_iommu; mutex_init(&vdev->igate); + pm_runtime_enable(vdev->device); return 0; + +put_iommu: + vfio_iommu_group_put(group, dev); +put_reset: + vfio_platform_put_reset(vdev); + return ret; } EXPORT_SYMBOL_GPL(vfio_platform_probe_common); @@ -703,6 +716,7 @@ struct vfio_platform_device *vfio_platform_remove_common(struct device *dev) vdev = vfio_del_group_dev(dev); if (vdev) { + pm_runtime_disable(vdev->device); vfio_platform_put_reset(vdev); vfio_iommu_group_put(dev->iommu_group, dev); } diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c index 721f97f8dac1..64833879f75d 100644 --- a/drivers/vfio/vfio.c +++ b/drivers/vfio/vfio.c @@ -630,8 +630,6 @@ static const char * const vfio_driver_whitelist[] = { "pci-stub" }; static bool vfio_dev_whitelisted(struct device *dev, struct device_driver *drv) { - int i; - if (dev_is_pci(dev)) { struct pci_dev *pdev = to_pci_dev(dev); @@ -639,12 +637,9 @@ static bool vfio_dev_whitelisted(struct device *dev, struct device_driver *drv) return true; } - for (i = 0; i < ARRAY_SIZE(vfio_driver_whitelist); i++) { - if (!strcmp(drv->name, vfio_driver_whitelist[i])) - return true; - } - - return false; + return match_string(vfio_driver_whitelist, + ARRAY_SIZE(vfio_driver_whitelist), + drv->name) >= 0; } /* diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c index 3c082451ab1a..2c75b33db4ac 100644 --- a/drivers/vfio/vfio_iommu_type1.c +++ b/drivers/vfio/vfio_iommu_type1.c @@ -83,6 +83,7 @@ struct vfio_dma { size_t size; /* Map size (bytes) */ int prot; /* IOMMU_READ/WRITE */ bool iommu_mapped; + bool lock_cap; /* capable(CAP_IPC_LOCK) */ struct task_struct *task; struct rb_root pfn_list; /* Ex-user pinned pfn list */ }; @@ -253,29 +254,25 @@ static int vfio_iova_put_vfio_pfn(struct vfio_dma *dma, struct vfio_pfn *vpfn) return ret; } -static int vfio_lock_acct(struct task_struct *task, long npage, bool *lock_cap) +static int vfio_lock_acct(struct vfio_dma *dma, long npage, bool async) { struct mm_struct *mm; - bool is_current; int ret; if (!npage) return 0; - is_current = (task->mm == current->mm); - - mm = is_current ? task->mm : get_task_mm(task); + mm = async ? get_task_mm(dma->task) : dma->task->mm; if (!mm) return -ESRCH; /* process exited */ ret = down_write_killable(&mm->mmap_sem); if (!ret) { if (npage > 0) { - if (lock_cap ? !*lock_cap : - !has_capability(task, CAP_IPC_LOCK)) { + if (!dma->lock_cap) { unsigned long limit; - limit = task_rlimit(task, + limit = task_rlimit(dma->task, RLIMIT_MEMLOCK) >> PAGE_SHIFT; if (mm->locked_vm + npage > limit) @@ -289,7 +286,7 @@ static int vfio_lock_acct(struct task_struct *task, long npage, bool *lock_cap) up_write(&mm->mmap_sem); } - if (!is_current) + if (async) mmput(mm); return ret; @@ -400,7 +397,7 @@ static int vaddr_get_pfn(struct mm_struct *mm, unsigned long vaddr, */ static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr, long npage, unsigned long *pfn_base, - bool lock_cap, unsigned long limit) + unsigned long limit) { unsigned long pfn = 0; long ret, pinned = 0, lock_acct = 0; @@ -423,7 +420,7 @@ static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr, * pages are already counted against the user. */ if (!rsvd && !vfio_find_vpfn(dma, iova)) { - if (!lock_cap && current->mm->locked_vm + 1 > limit) { + if (!dma->lock_cap && current->mm->locked_vm + 1 > limit) { put_pfn(*pfn_base, dma->prot); pr_warn("%s: RLIMIT_MEMLOCK (%ld) exceeded\n", __func__, limit << PAGE_SHIFT); @@ -449,7 +446,7 @@ static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr, } if (!rsvd && !vfio_find_vpfn(dma, iova)) { - if (!lock_cap && + if (!dma->lock_cap && current->mm->locked_vm + lock_acct + 1 > limit) { put_pfn(pfn, dma->prot); pr_warn("%s: RLIMIT_MEMLOCK (%ld) exceeded\n", @@ -462,7 +459,7 @@ static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr, } out: - ret = vfio_lock_acct(current, lock_acct, &lock_cap); + ret = vfio_lock_acct(dma, lock_acct, false); unpin_out: if (ret) { @@ -493,7 +490,7 @@ static long vfio_unpin_pages_remote(struct vfio_dma *dma, dma_addr_t iova, } if (do_accounting) - vfio_lock_acct(dma->task, locked - unlocked, NULL); + vfio_lock_acct(dma, locked - unlocked, true); return unlocked; } @@ -510,7 +507,7 @@ static int vfio_pin_page_external(struct vfio_dma *dma, unsigned long vaddr, ret = vaddr_get_pfn(mm, vaddr, dma->prot, pfn_base); if (!ret && do_accounting && !is_invalid_reserved_pfn(*pfn_base)) { - ret = vfio_lock_acct(dma->task, 1, NULL); + ret = vfio_lock_acct(dma, 1, true); if (ret) { put_pfn(*pfn_base, dma->prot); if (ret == -ENOMEM) @@ -537,7 +534,7 @@ static int vfio_unpin_page_external(struct vfio_dma *dma, dma_addr_t iova, unlocked = vfio_iova_put_vfio_pfn(dma, vpfn); if (do_accounting) - vfio_lock_acct(dma->task, -unlocked, NULL); + vfio_lock_acct(dma, -unlocked, true); return unlocked; } @@ -829,7 +826,7 @@ static long vfio_unmap_unpin(struct vfio_iommu *iommu, struct vfio_dma *dma, unlocked += vfio_sync_unpin(dma, domain, &unmapped_region_list); if (do_accounting) { - vfio_lock_acct(dma->task, -unlocked, NULL); + vfio_lock_acct(dma, -unlocked, true); return 0; } return unlocked; @@ -1044,14 +1041,12 @@ static int vfio_pin_map_dma(struct vfio_iommu *iommu, struct vfio_dma *dma, size_t size = map_size; long npage; unsigned long pfn, limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; - bool lock_cap = capable(CAP_IPC_LOCK); int ret = 0; while (size) { /* Pin a contiguous chunk of memory */ npage = vfio_pin_pages_remote(dma, vaddr + dma->size, - size >> PAGE_SHIFT, &pfn, - lock_cap, limit); + size >> PAGE_SHIFT, &pfn, limit); if (npage <= 0) { WARN_ON(!npage); ret = (int)npage; @@ -1126,8 +1121,36 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu, dma->iova = iova; dma->vaddr = vaddr; dma->prot = prot; - get_task_struct(current); - dma->task = current; + + /* + * We need to be able to both add to a task's locked memory and test + * against the locked memory limit and we need to be able to do both + * outside of this call path as pinning can be asynchronous via the + * external interfaces for mdev devices. RLIMIT_MEMLOCK requires a + * task_struct and VM locked pages requires an mm_struct, however + * holding an indefinite mm reference is not recommended, therefore we + * only hold a reference to a task. We could hold a reference to + * current, however QEMU uses this call path through vCPU threads, + * which can be killed resulting in a NULL mm and failure in the unmap + * path when called via a different thread. Avoid this problem by + * using the group_leader as threads within the same group require + * both CLONE_THREAD and CLONE_VM and will therefore use the same + * mm_struct. + * + * Previously we also used the task for testing CAP_IPC_LOCK at the + * time of pinning and accounting, however has_capability() makes use + * of real_cred, a copy-on-write field, so we can't guarantee that it + * matches group_leader, or in fact that it might not change by the + * time it's evaluated. If a process were to call MAP_DMA with + * CAP_IPC_LOCK but later drop it, it doesn't make sense that they + * possibly see different results for an iommu_mapped vfio_dma vs + * externally mapped. Therefore track CAP_IPC_LOCK in vfio_dma at the + * time of calling MAP_DMA. + */ + get_task_struct(current->group_leader); + dma->task = current->group_leader; + dma->lock_cap = capable(CAP_IPC_LOCK); + dma->pfn_list = RB_ROOT; /* Insert zero-sized and grow as we map chunks of it */ @@ -1162,7 +1185,6 @@ static int vfio_iommu_replay(struct vfio_iommu *iommu, struct vfio_domain *d; struct rb_node *n; unsigned long limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; - bool lock_cap = capable(CAP_IPC_LOCK); int ret; /* Arbitrarily pick the first domain in the list for lookups */ @@ -1209,8 +1231,7 @@ static int vfio_iommu_replay(struct vfio_iommu *iommu, npage = vfio_pin_pages_remote(dma, vaddr, n >> PAGE_SHIFT, - &pfn, lock_cap, - limit); + &pfn, limit); if (npage <= 0) { WARN_ON(!npage); ret = (int)npage; @@ -1487,7 +1508,7 @@ static void vfio_iommu_unmap_unpin_reaccount(struct vfio_iommu *iommu) if (!is_invalid_reserved_pfn(vpfn->pfn)) locked++; } - vfio_lock_acct(dma->task, locked - unlocked, NULL); + vfio_lock_acct(dma, locked - unlocked, true); } } diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index e7cf7d21cfb5..686dc670fd29 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -274,8 +274,10 @@ static int vhost_net_set_ubuf_info(struct vhost_net *n) zcopy = vhost_net_zcopy_mask & (0x1 << i); if (!zcopy) continue; - n->vqs[i].ubuf_info = kmalloc(sizeof(*n->vqs[i].ubuf_info) * - UIO_MAXIOV, GFP_KERNEL); + n->vqs[i].ubuf_info = + kmalloc_array(UIO_MAXIOV, + sizeof(*n->vqs[i].ubuf_info), + GFP_KERNEL); if (!n->vqs[i].ubuf_info) goto err; } @@ -943,7 +945,7 @@ static int vhost_net_open(struct inode *inode, struct file *f) n = kvmalloc(sizeof *n, GFP_KERNEL | __GFP_RETRY_MAYFAIL); if (!n) return -ENOMEM; - vqs = kmalloc(VHOST_NET_VQ_MAX * sizeof(*vqs), GFP_KERNEL); + vqs = kmalloc_array(VHOST_NET_VQ_MAX, sizeof(*vqs), GFP_KERNEL); if (!vqs) { kvfree(n); return -ENOMEM; diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index 7ad57094d736..17fcd3b2e686 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -1378,7 +1378,7 @@ static int vhost_scsi_open(struct inode *inode, struct file *f) goto err_vs; } - vqs = kmalloc(VHOST_SCSI_MAX_VQ * sizeof(*vqs), GFP_KERNEL); + vqs = kmalloc_array(VHOST_SCSI_MAX_VQ, sizeof(*vqs), GFP_KERNEL); if (!vqs) goto err_vqs; @@ -1685,22 +1685,25 @@ static int vhost_scsi_nexus_cb(struct se_portal_group *se_tpg, for (i = 0; i < VHOST_SCSI_DEFAULT_TAGS; i++) { tv_cmd = &((struct vhost_scsi_cmd *)se_sess->sess_cmd_map)[i]; - tv_cmd->tvc_sgl = kzalloc(sizeof(struct scatterlist) * - VHOST_SCSI_PREALLOC_SGLS, GFP_KERNEL); + tv_cmd->tvc_sgl = kcalloc(VHOST_SCSI_PREALLOC_SGLS, + sizeof(struct scatterlist), + GFP_KERNEL); if (!tv_cmd->tvc_sgl) { pr_err("Unable to allocate tv_cmd->tvc_sgl\n"); goto out; } - tv_cmd->tvc_upages = kzalloc(sizeof(struct page *) * - VHOST_SCSI_PREALLOC_UPAGES, GFP_KERNEL); + tv_cmd->tvc_upages = kcalloc(VHOST_SCSI_PREALLOC_UPAGES, + sizeof(struct page *), + GFP_KERNEL); if (!tv_cmd->tvc_upages) { pr_err("Unable to allocate tv_cmd->tvc_upages\n"); goto out; } - tv_cmd->tvc_prot_sgl = kzalloc(sizeof(struct scatterlist) * - VHOST_SCSI_PREALLOC_PROT_SGLS, GFP_KERNEL); + tv_cmd->tvc_prot_sgl = kcalloc(VHOST_SCSI_PREALLOC_PROT_SGLS, + sizeof(struct scatterlist), + GFP_KERNEL); if (!tv_cmd->tvc_prot_sgl) { pr_err("Unable to allocate tv_cmd->tvc_prot_sgl\n"); goto out; diff --git a/drivers/vhost/test.c b/drivers/vhost/test.c index 906b8f0f19f7..40589850eb33 100644 --- a/drivers/vhost/test.c +++ b/drivers/vhost/test.c @@ -107,7 +107,7 @@ static int vhost_test_open(struct inode *inode, struct file *f) if (!n) return -ENOMEM; - vqs = kmalloc(VHOST_TEST_VQ_MAX * sizeof(*vqs), GFP_KERNEL); + vqs = kmalloc_array(VHOST_TEST_VQ_MAX, sizeof(*vqs), GFP_KERNEL); if (!vqs) { kfree(n); return -ENOMEM; diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 895eaa25807c..a502f1af4a21 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -385,10 +385,13 @@ static long vhost_dev_alloc_iovecs(struct vhost_dev *dev) for (i = 0; i < dev->nvqs; ++i) { vq = dev->vqs[i]; - vq->indirect = kmalloc(sizeof *vq->indirect * UIO_MAXIOV, - GFP_KERNEL); - vq->log = kmalloc(sizeof *vq->log * UIO_MAXIOV, GFP_KERNEL); - vq->heads = kmalloc(sizeof *vq->heads * UIO_MAXIOV, GFP_KERNEL); + vq->indirect = kmalloc_array(UIO_MAXIOV, + sizeof(*vq->indirect), + GFP_KERNEL); + vq->log = kmalloc_array(UIO_MAXIOV, sizeof(*vq->log), + GFP_KERNEL); + vq->heads = kmalloc_array(UIO_MAXIOV, sizeof(*vq->heads), + GFP_KERNEL); if (!vq->indirect || !vq->log || !vq->heads) goto err_nomem; } @@ -1286,7 +1289,8 @@ static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m) return -EOPNOTSUPP; if (mem.nregions > max_mem_regions) return -E2BIG; - newmem = kvzalloc(size + mem.nregions * sizeof(*m->regions), GFP_KERNEL); + newmem = kvzalloc(struct_size(newmem, regions, mem.nregions), + GFP_KERNEL); if (!newmem) return -ENOMEM; @@ -2345,6 +2349,9 @@ struct vhost_msg_node *vhost_new_msg(struct vhost_virtqueue *vq, int type) struct vhost_msg_node *node = kmalloc(sizeof *node, GFP_KERNEL); if (!node) return NULL; + + /* Make sure all padding within the structure is initialized. */ + memset(&node->msg, 0, sizeof node->msg); node->vq = vq; node->msg.type = type; return node; diff --git a/drivers/vhost/vringh.c b/drivers/vhost/vringh.c index bb8971f2a634..a94d700a4503 100644 --- a/drivers/vhost/vringh.c +++ b/drivers/vhost/vringh.c @@ -191,7 +191,7 @@ static int resize_iovec(struct vringh_kiov *iov, gfp_t gfp) if (flag) new = krealloc(iov->iov, new_num * sizeof(struct iovec), gfp); else { - new = kmalloc(new_num * sizeof(struct iovec), gfp); + new = kmalloc_array(new_num, sizeof(struct iovec), gfp); if (new) { memcpy(new, iov->iov, iov->max_num * sizeof(struct iovec)); diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 4e1d2ad50ba1..2919e2334052 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -150,6 +150,13 @@ config LCD_HX8357 If you have a HX-8357 LCD panel, say Y to enable its LCD control driver. + config LCD_OTM3225A + tristate "ORISE Technology OTM3225A support" + depends on SPI + help + If you have a panel based on the OTM3225A controller + chip then say y to include a driver for it. + endif # LCD_CLASS_DEVICE # @@ -467,6 +474,12 @@ config BACKLIGHT_ARCXCNN If you have an ARCxCnnnn family backlight say Y to enable the backlight driver. +config BACKLIGHT_RAVE_SP + tristate "RAVE SP Backlight driver" + depends on RAVE_SP_CORE + help + Support for backlight control on RAVE SP device. + endif # BACKLIGHT_CLASS_DEVICE endif # BACKLIGHT_LCD_SUPPORT diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index 5e28f01c8391..0dcc2c745c03 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_LCD_LD9040) += ld9040.o obj-$(CONFIG_LCD_LMS283GF05) += lms283gf05.o obj-$(CONFIG_LCD_LMS501KF03) += lms501kf03.o obj-$(CONFIG_LCD_LTV350QV) += ltv350qv.o +obj-$(CONFIG_LCD_OTM3225A) += otm3225a.o obj-$(CONFIG_LCD_PLATFORM) += platform_lcd.o obj-$(CONFIG_LCD_S6E63M0) += s6e63m0.o obj-$(CONFIG_LCD_TDO24M) += tdo24m.o @@ -57,3 +58,4 @@ obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o obj-$(CONFIG_BACKLIGHT_TPS65217) += tps65217_bl.o obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o obj-$(CONFIG_BACKLIGHT_ARCXCNN) += arcxcnn_bl.o +obj-$(CONFIG_BACKLIGHT_RAVE_SP) += rave-sp-backlight.o diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c index e7315bf14d60..16119bde9750 100644 --- a/drivers/video/backlight/adp8860_bl.c +++ b/drivers/video/backlight/adp8860_bl.c @@ -223,7 +223,7 @@ static int adp8860_led_probe(struct i2c_client *client) struct led_info *cur_led; int ret, i; - led = devm_kzalloc(&client->dev, sizeof(*led) * pdata->num_leds, + led = devm_kcalloc(&client->dev, pdata->num_leds, sizeof(*led), GFP_KERNEL); if (led == NULL) return -ENOMEM; diff --git a/drivers/video/backlight/adp8870_bl.c b/drivers/video/backlight/adp8870_bl.c index 058d1def2d1f..4fec9aa92d9b 100644 --- a/drivers/video/backlight/adp8870_bl.c +++ b/drivers/video/backlight/adp8870_bl.c @@ -246,7 +246,7 @@ static int adp8870_led_probe(struct i2c_client *client) struct led_info *cur_led; int ret, i; - led = devm_kzalloc(&client->dev, pdata->num_leds * sizeof(*led), + led = devm_kcalloc(&client->dev, pdata->num_leds, sizeof(*led), GFP_KERNEL); if (led == NULL) return -ENOMEM; diff --git a/drivers/video/backlight/as3711_bl.c b/drivers/video/backlight/as3711_bl.c index 734a9158946b..ca544aa764b8 100644 --- a/drivers/video/backlight/as3711_bl.c +++ b/drivers/video/backlight/as3711_bl.c @@ -28,8 +28,6 @@ enum as3711_bl_type { struct as3711_bl_data { bool powered; - const char *fb_name; - struct device *fb_dev; enum as3711_bl_type type; int brightness; struct backlight_device *bl; @@ -262,10 +260,10 @@ static int as3711_bl_register(struct platform_device *pdev, static int as3711_backlight_parse_dt(struct device *dev) { struct as3711_bl_pdata *pdata = dev_get_platdata(dev); - struct device_node *bl = - of_find_node_by_name(dev->parent->of_node, "backlight"), *fb; + struct device_node *bl, *fb; int ret; + bl = of_get_child_by_name(dev->parent->of_node, "backlight"); if (!bl) { dev_dbg(dev, "backlight node not found\n"); return -ENODEV; @@ -273,26 +271,30 @@ static int as3711_backlight_parse_dt(struct device *dev) fb = of_parse_phandle(bl, "su1-dev", 0); if (fb) { - pdata->su1_fb = fb->full_name; + of_node_put(fb); + + pdata->su1_fb = true; ret = of_property_read_u32(bl, "su1-max-uA", &pdata->su1_max_uA); if (pdata->su1_max_uA <= 0) ret = -EINVAL; if (ret < 0) - return ret; + goto err_put_bl; } fb = of_parse_phandle(bl, "su2-dev", 0); if (fb) { int count = 0; - pdata->su2_fb = fb->full_name; + of_node_put(fb); + + pdata->su2_fb = true; ret = of_property_read_u32(bl, "su2-max-uA", &pdata->su2_max_uA); if (pdata->su2_max_uA <= 0) ret = -EINVAL; if (ret < 0) - return ret; + goto err_put_bl; if (of_find_property(bl, "su2-feedback-voltage", NULL)) { pdata->su2_feedback = AS3711_SU2_VOLTAGE; @@ -314,8 +316,10 @@ static int as3711_backlight_parse_dt(struct device *dev) pdata->su2_feedback = AS3711_SU2_CURR_AUTO; count++; } - if (count != 1) - return -EINVAL; + if (count != 1) { + ret = -EINVAL; + goto err_put_bl; + } count = 0; if (of_find_property(bl, "su2-fbprot-lx-sd4", NULL)) { @@ -334,8 +338,10 @@ static int as3711_backlight_parse_dt(struct device *dev) pdata->su2_fbprot = AS3711_SU2_GPIO4; count++; } - if (count != 1) - return -EINVAL; + if (count != 1) { + ret = -EINVAL; + goto err_put_bl; + } count = 0; if (of_find_property(bl, "su2-auto-curr1", NULL)) { @@ -355,11 +361,20 @@ static int as3711_backlight_parse_dt(struct device *dev) * At least one su2-auto-curr* must be specified iff * AS3711_SU2_CURR_AUTO is used */ - if (!count ^ (pdata->su2_feedback != AS3711_SU2_CURR_AUTO)) - return -EINVAL; + if (!count ^ (pdata->su2_feedback != AS3711_SU2_CURR_AUTO)) { + ret = -EINVAL; + goto err_put_bl; + } } + of_node_put(bl); + return 0; + +err_put_bl: + of_node_put(bl); + + return ret; } static int as3711_backlight_probe(struct platform_device *pdev) @@ -412,7 +427,6 @@ static int as3711_backlight_probe(struct platform_device *pdev) if (pdata->su1_fb) { su = &supply->su1; - su->fb_name = pdata->su1_fb; su->type = AS3711_BL_SU1; max_brightness = min(pdata->su1_max_uA, 31); @@ -423,7 +437,6 @@ static int as3711_backlight_probe(struct platform_device *pdev) if (pdata->su2_fb) { su = &supply->su2; - su->fb_name = pdata->su2_fb; su->type = AS3711_BL_SU2; switch (pdata->su2_fbprot) { diff --git a/drivers/video/backlight/generic_bl.c b/drivers/video/backlight/generic_bl.c index 67dfb939a514..4dea91acea13 100644 --- a/drivers/video/backlight/generic_bl.c +++ b/drivers/video/backlight/generic_bl.c @@ -21,9 +21,6 @@ static int genericbl_intensity; static struct backlight_device *generic_backlight_device; static struct generic_bl_info *bl_machinfo; -/* Flag to signal when the battery is low */ -#define GENERICBL_BATTLOW BL_CORE_DRIVER1 - static int genericbl_send_intensity(struct backlight_device *bd) { int intensity = bd->props.brightness; @@ -34,8 +31,6 @@ static int genericbl_send_intensity(struct backlight_device *bd) intensity = 0; if (bd->props.state & BL_CORE_SUSPENDED) intensity = 0; - if (bd->props.state & GENERICBL_BATTLOW) - intensity &= bl_machinfo->limit_mask; bl_machinfo->set_bl_intensity(intensity); diff --git a/drivers/video/backlight/lp855x_bl.c b/drivers/video/backlight/lp855x_bl.c index 939f057836e1..73612485ed07 100644 --- a/drivers/video/backlight/lp855x_bl.c +++ b/drivers/video/backlight/lp855x_bl.c @@ -374,7 +374,7 @@ static int lp855x_parse_dt(struct lp855x *lp) struct device_node *child; int i = 0; - rom = devm_kzalloc(dev, sizeof(*rom) * rom_length, GFP_KERNEL); + rom = devm_kcalloc(dev, rom_length, sizeof(*rom), GFP_KERNEL); if (!rom) return -ENOMEM; diff --git a/drivers/video/backlight/max8925_bl.c b/drivers/video/backlight/max8925_bl.c index 7b738d60ecc2..f3aa6088f1d9 100644 --- a/drivers/video/backlight/max8925_bl.c +++ b/drivers/video/backlight/max8925_bl.c @@ -116,7 +116,7 @@ static void max8925_backlight_dt_init(struct platform_device *pdev) if (!pdata) return; - np = of_find_node_by_name(nproot, "backlight"); + np = of_get_child_by_name(nproot, "backlight"); if (!np) { dev_err(&pdev->dev, "failed to find backlight node\n"); return; @@ -125,6 +125,8 @@ static void max8925_backlight_dt_init(struct platform_device *pdev) if (!of_property_read_u32(np, "maxim,max8925-dual-string", &val)) pdata->dual_string = val; + of_node_put(np); + pdev->dev.platform_data = pdata; } diff --git a/drivers/video/backlight/otm3225a.c b/drivers/video/backlight/otm3225a.c new file mode 100644 index 000000000000..2472e2167aae --- /dev/null +++ b/drivers/video/backlight/otm3225a.c @@ -0,0 +1,252 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Driver for ORISE Technology OTM3225A SOC for TFT LCD + * Copyright (C) 2017, EETS GmbH, Felix Brack <fb@ltec.ch> + * + * This driver implements a lcd device for the ORISE OTM3225A display + * controller. The control interface to the display is SPI and the display's + * memory is updated over the 16-bit RGB interface. + * The main source of information for writing this driver was provided by the + * OTM3225A datasheet from ORISE Technology. Some information arise from the + * ILI9328 datasheet from ILITEK as well as from the datasheets and sample code + * provided by Crystalfontz America Inc. who sells the CFAF240320A-032T, a 3.2" + * TFT LC display using the OTM3225A controller. + */ + +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/lcd.h> +#include <linux/module.h> +#include <linux/spi/spi.h> + +#define OTM3225A_INDEX_REG 0x70 +#define OTM3225A_DATA_REG 0x72 + +/* instruction register list */ +#define DRIVER_OUTPUT_CTRL_1 0x01 +#define DRIVER_WAVEFORM_CTRL 0x02 +#define ENTRY_MODE 0x03 +#define SCALING_CTRL 0x04 +#define DISPLAY_CTRL_1 0x07 +#define DISPLAY_CTRL_2 0x08 +#define DISPLAY_CTRL_3 0x09 +#define FRAME_CYCLE_CTRL 0x0A +#define EXT_DISP_IFACE_CTRL_1 0x0C +#define FRAME_MAKER_POS 0x0D +#define EXT_DISP_IFACE_CTRL_2 0x0F +#define POWER_CTRL_1 0x10 +#define POWER_CTRL_2 0x11 +#define POWER_CTRL_3 0x12 +#define POWER_CTRL_4 0x13 +#define GRAM_ADDR_HORIZ_SET 0x20 +#define GRAM_ADDR_VERT_SET 0x21 +#define GRAM_READ_WRITE 0x22 +#define POWER_CTRL_7 0x29 +#define FRAME_RATE_CTRL 0x2B +#define GAMMA_CTRL_1 0x30 +#define GAMMA_CTRL_2 0x31 +#define GAMMA_CTRL_3 0x32 +#define GAMMA_CTRL_4 0x35 +#define GAMMA_CTRL_5 0x36 +#define GAMMA_CTRL_6 0x37 +#define GAMMA_CTRL_7 0x38 +#define GAMMA_CTRL_8 0x39 +#define GAMMA_CTRL_9 0x3C +#define GAMMA_CTRL_10 0x3D +#define WINDOW_HORIZ_RAM_START 0x50 +#define WINDOW_HORIZ_RAM_END 0x51 +#define WINDOW_VERT_RAM_START 0x52 +#define WINDOW_VERT_RAM_END 0x53 +#define DRIVER_OUTPUT_CTRL_2 0x60 +#define BASE_IMG_DISPLAY_CTRL 0x61 +#define VERT_SCROLL_CTRL 0x6A +#define PD1_DISPLAY_POS 0x80 +#define PD1_RAM_START 0x81 +#define PD1_RAM_END 0x82 +#define PD2_DISPLAY_POS 0x83 +#define PD2_RAM_START 0x84 +#define PD2_RAM_END 0x85 +#define PANEL_IFACE_CTRL_1 0x90 +#define PANEL_IFACE_CTRL_2 0x92 +#define PANEL_IFACE_CTRL_4 0x95 +#define PANEL_IFACE_CTRL_5 0x97 + +struct otm3225a_data { + struct spi_device *spi; + struct lcd_device *ld; + int power; +}; + +struct otm3225a_spi_instruction { + unsigned char reg; /* register to write */ + unsigned short value; /* data to write to 'reg' */ + unsigned short delay; /* delay in ms after write */ +}; + +static struct otm3225a_spi_instruction display_init[] = { + { DRIVER_OUTPUT_CTRL_1, 0x0000, 0 }, + { DRIVER_WAVEFORM_CTRL, 0x0700, 0 }, + { ENTRY_MODE, 0x50A0, 0 }, + { SCALING_CTRL, 0x0000, 0 }, + { DISPLAY_CTRL_2, 0x0606, 0 }, + { DISPLAY_CTRL_3, 0x0000, 0 }, + { FRAME_CYCLE_CTRL, 0x0000, 0 }, + { EXT_DISP_IFACE_CTRL_1, 0x0000, 0 }, + { FRAME_MAKER_POS, 0x0000, 0 }, + { EXT_DISP_IFACE_CTRL_2, 0x0002, 0 }, + { POWER_CTRL_2, 0x0007, 0 }, + { POWER_CTRL_3, 0x0000, 0 }, + { POWER_CTRL_4, 0x0000, 200 }, + { DISPLAY_CTRL_1, 0x0101, 0 }, + { POWER_CTRL_1, 0x12B0, 0 }, + { POWER_CTRL_2, 0x0007, 0 }, + { POWER_CTRL_3, 0x01BB, 50 }, + { POWER_CTRL_4, 0x0013, 0 }, + { POWER_CTRL_7, 0x0010, 50 }, + { GAMMA_CTRL_1, 0x000A, 0 }, + { GAMMA_CTRL_2, 0x1326, 0 }, + { GAMMA_CTRL_3, 0x0A29, 0 }, + { GAMMA_CTRL_4, 0x0A0A, 0 }, + { GAMMA_CTRL_5, 0x1E03, 0 }, + { GAMMA_CTRL_6, 0x031E, 0 }, + { GAMMA_CTRL_7, 0x0706, 0 }, + { GAMMA_CTRL_8, 0x0303, 0 }, + { GAMMA_CTRL_9, 0x010E, 0 }, + { GAMMA_CTRL_10, 0x040E, 0 }, + { WINDOW_HORIZ_RAM_START, 0x0000, 0 }, + { WINDOW_HORIZ_RAM_END, 0x00EF, 0 }, + { WINDOW_VERT_RAM_START, 0x0000, 0 }, + { WINDOW_VERT_RAM_END, 0x013F, 0 }, + { DRIVER_OUTPUT_CTRL_2, 0x2700, 0 }, + { BASE_IMG_DISPLAY_CTRL, 0x0001, 0 }, + { VERT_SCROLL_CTRL, 0x0000, 0 }, + { PD1_DISPLAY_POS, 0x0000, 0 }, + { PD1_RAM_START, 0x0000, 0 }, + { PD1_RAM_END, 0x0000, 0 }, + { PD2_DISPLAY_POS, 0x0000, 0 }, + { PD2_RAM_START, 0x0000, 0 }, + { PD2_RAM_END, 0x0000, 0 }, + { PANEL_IFACE_CTRL_1, 0x0010, 0 }, + { PANEL_IFACE_CTRL_2, 0x0000, 0 }, + { PANEL_IFACE_CTRL_4, 0x0210, 0 }, + { PANEL_IFACE_CTRL_5, 0x0000, 0 }, + { DISPLAY_CTRL_1, 0x0133, 0 }, +}; + +static struct otm3225a_spi_instruction display_enable_rgb_interface[] = { + { ENTRY_MODE, 0x1080, 0 }, + { GRAM_ADDR_HORIZ_SET, 0x0000, 0 }, + { GRAM_ADDR_VERT_SET, 0x0000, 0 }, + { EXT_DISP_IFACE_CTRL_1, 0x0111, 500 }, +}; + +static struct otm3225a_spi_instruction display_off[] = { + { DISPLAY_CTRL_1, 0x0131, 100 }, + { DISPLAY_CTRL_1, 0x0130, 100 }, + { DISPLAY_CTRL_1, 0x0100, 0 }, + { POWER_CTRL_1, 0x0280, 0 }, + { POWER_CTRL_3, 0x018B, 0 }, +}; + +static struct otm3225a_spi_instruction display_on[] = { + { POWER_CTRL_1, 0x1280, 0 }, + { DISPLAY_CTRL_1, 0x0101, 100 }, + { DISPLAY_CTRL_1, 0x0121, 0 }, + { DISPLAY_CTRL_1, 0x0123, 100 }, + { DISPLAY_CTRL_1, 0x0133, 10 }, +}; + +static void otm3225a_write(struct spi_device *spi, + struct otm3225a_spi_instruction *instruction, + unsigned int count) +{ + unsigned char buf[3]; + + while (count--) { + /* address register using index register */ + buf[0] = OTM3225A_INDEX_REG; + buf[1] = 0x00; + buf[2] = instruction->reg; + spi_write(spi, buf, 3); + + /* write data to addressed register */ + buf[0] = OTM3225A_DATA_REG; + buf[1] = (instruction->value >> 8) & 0xff; + buf[2] = instruction->value & 0xff; + spi_write(spi, buf, 3); + + /* execute delay if any */ + if (instruction->delay) + msleep(instruction->delay); + instruction++; + } +} + +static int otm3225a_set_power(struct lcd_device *ld, int power) +{ + struct otm3225a_data *dd = lcd_get_data(ld); + + if (power == dd->power) + return 0; + + if (power > FB_BLANK_UNBLANK) + otm3225a_write(dd->spi, display_off, ARRAY_SIZE(display_off)); + else + otm3225a_write(dd->spi, display_on, ARRAY_SIZE(display_on)); + dd->power = power; + + return 0; +} + +static int otm3225a_get_power(struct lcd_device *ld) +{ + struct otm3225a_data *dd = lcd_get_data(ld); + + return dd->power; +} + +static struct lcd_ops otm3225a_ops = { + .set_power = otm3225a_set_power, + .get_power = otm3225a_get_power, +}; + +static int otm3225a_probe(struct spi_device *spi) +{ + struct otm3225a_data *dd; + struct lcd_device *ld; + struct device *dev = &spi->dev; + + dd = devm_kzalloc(dev, sizeof(struct otm3225a_data), GFP_KERNEL); + if (dd == NULL) + return -ENOMEM; + + ld = devm_lcd_device_register(dev, dev_name(dev), dev, dd, + &otm3225a_ops); + if (IS_ERR(ld)) + return PTR_ERR(ld); + + dd->spi = spi; + dd->ld = ld; + dev_set_drvdata(dev, dd); + + dev_info(dev, "Initializing and switching to RGB interface"); + otm3225a_write(spi, display_init, ARRAY_SIZE(display_init)); + otm3225a_write(spi, display_enable_rgb_interface, + ARRAY_SIZE(display_enable_rgb_interface)); + return 0; +} + +static struct spi_driver otm3225a_driver = { + .driver = { + .name = "otm3225a", + .owner = THIS_MODULE, + }, + .probe = otm3225a_probe, +}; + +module_spi_driver(otm3225a_driver); + +MODULE_AUTHOR("Felix Brack <fb@ltec.ch>"); +MODULE_DESCRIPTION("OTM3225A TFT LCD driver"); +MODULE_VERSION("1.0.0"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/video/backlight/pandora_bl.c b/drivers/video/backlight/pandora_bl.c index a186bc677c7d..9618766e3866 100644 --- a/drivers/video/backlight/pandora_bl.c +++ b/drivers/video/backlight/pandora_bl.c @@ -35,11 +35,15 @@ #define MAX_VALUE 63 #define MAX_USER_VALUE (MAX_VALUE - MIN_VALUE) -#define PANDORABL_WAS_OFF BL_CORE_DRIVER1 +struct pandora_private { + unsigned old_state; +#define PANDORABL_WAS_OFF 1 +}; static int pandora_backlight_update_status(struct backlight_device *bl) { int brightness = bl->props.brightness; + struct pandora_private *priv = bl_get_data(bl); u8 r; if (bl->props.power != FB_BLANK_UNBLANK) @@ -53,7 +57,7 @@ static int pandora_backlight_update_status(struct backlight_device *bl) brightness = MAX_USER_VALUE; if (brightness == 0) { - if (bl->props.state & PANDORABL_WAS_OFF) + if (priv->old_state == PANDORABL_WAS_OFF) goto done; /* first disable PWM0 output, then clock */ @@ -66,7 +70,7 @@ static int pandora_backlight_update_status(struct backlight_device *bl) goto done; } - if (bl->props.state & PANDORABL_WAS_OFF) { + if (priv->old_state == PANDORABL_WAS_OFF) { /* * set PWM duty cycle to max. TPS61161 seems to use this * to calibrate it's PWM sensitivity when it starts. @@ -93,9 +97,9 @@ static int pandora_backlight_update_status(struct backlight_device *bl) done: if (brightness != 0) - bl->props.state &= ~PANDORABL_WAS_OFF; + priv->old_state = 0; else - bl->props.state |= PANDORABL_WAS_OFF; + priv->old_state = PANDORABL_WAS_OFF; return 0; } @@ -109,13 +113,20 @@ static int pandora_backlight_probe(struct platform_device *pdev) { struct backlight_properties props; struct backlight_device *bl; + struct pandora_private *priv; u8 r; + priv = devm_kmalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) { + dev_err(&pdev->dev, "failed to allocate driver private data\n"); + return -ENOMEM; + } + memset(&props, 0, sizeof(props)); props.max_brightness = MAX_USER_VALUE; props.type = BACKLIGHT_RAW; bl = devm_backlight_device_register(&pdev->dev, pdev->name, &pdev->dev, - NULL, &pandora_backlight_ops, &props); + priv, &pandora_backlight_ops, &props); if (IS_ERR(bl)) { dev_err(&pdev->dev, "failed to register backlight\n"); return PTR_ERR(bl); @@ -126,7 +137,7 @@ static int pandora_backlight_probe(struct platform_device *pdev) /* 64 cycle period, ON position 0 */ twl_i2c_write_u8(TWL_MODULE_PWM, 0x80, TWL_PWM0_ON); - bl->props.state |= PANDORABL_WAS_OFF; + priv->old_state = PANDORABL_WAS_OFF; bl->props.brightness = MAX_USER_VALUE; backlight_update_status(bl); diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index 1c2289ddd555..44ac5bde4e9d 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -10,6 +10,7 @@ * published by the Free Software Foundation. */ +#include <linux/delay.h> #include <linux/gpio/consumer.h> #include <linux/gpio.h> #include <linux/module.h> @@ -35,6 +36,8 @@ struct pwm_bl_data { struct gpio_desc *enable_gpio; unsigned int scale; bool legacy; + unsigned int post_pwm_on_delay; + unsigned int pwm_off_delay; int (*notify)(struct device *, int brightness); void (*notify_after)(struct device *, @@ -54,10 +57,14 @@ static void pwm_backlight_power_on(struct pwm_bl_data *pb, int brightness) if (err < 0) dev_err(pb->dev, "failed to enable power supply\n"); + pwm_enable(pb->pwm); + + if (pb->post_pwm_on_delay) + msleep(pb->post_pwm_on_delay); + if (pb->enable_gpio) gpiod_set_value_cansleep(pb->enable_gpio, 1); - pwm_enable(pb->pwm); pb->enabled = true; } @@ -66,12 +73,15 @@ static void pwm_backlight_power_off(struct pwm_bl_data *pb) if (!pb->enabled) return; - pwm_config(pb->pwm, 0, pb->period); - pwm_disable(pb->pwm); - if (pb->enable_gpio) gpiod_set_value_cansleep(pb->enable_gpio, 0); + if (pb->pwm_off_delay) + msleep(pb->pwm_off_delay); + + pwm_config(pb->pwm, 0, pb->period); + pwm_disable(pb->pwm); + regulator_disable(pb->power_supply); pb->enabled = false; } @@ -177,6 +187,14 @@ static int pwm_backlight_parse_dt(struct device *dev, data->max_brightness--; } + /* + * These values are optional and set as 0 by default, the out values + * are modified only if a valid u32 value can be decoded. + */ + of_property_read_u32(node, "post-pwm-on-delay-ms", + &data->post_pwm_on_delay); + of_property_read_u32(node, "pwm-off-delay-ms", &data->pwm_off_delay); + data->enable_gpio = -EINVAL; return 0; } @@ -275,6 +293,8 @@ static int pwm_backlight_probe(struct platform_device *pdev) pb->exit = data->exit; pb->dev = &pdev->dev; pb->enabled = false; + pb->post_pwm_on_delay = data->post_pwm_on_delay; + pb->pwm_off_delay = data->pwm_off_delay; pb->enable_gpio = devm_gpiod_get_optional(&pdev->dev, "enable", GPIOD_ASIS); @@ -301,14 +321,14 @@ static int pwm_backlight_probe(struct platform_device *pdev) /* * If the GPIO is not known to be already configured as output, that - * is, if gpiod_get_direction returns either GPIOF_DIR_IN or -EINVAL, - * change the direction to output and set the GPIO as active. + * is, if gpiod_get_direction returns either 1 or -EINVAL, change the + * direction to output and set the GPIO as active. * Do not force the GPIO to active when it was already output as it * could cause backlight flickering or we would enable the backlight too * early. Leave the decision of the initial backlight state for later. */ if (pb->enable_gpio && - gpiod_get_direction(pb->enable_gpio) != GPIOF_DIR_OUT) + gpiod_get_direction(pb->enable_gpio) != 0) gpiod_direction_output(pb->enable_gpio, 1); pb->power_supply = devm_regulator_get(&pdev->dev, "power"); diff --git a/drivers/video/backlight/rave-sp-backlight.c b/drivers/video/backlight/rave-sp-backlight.c new file mode 100644 index 000000000000..462f14a1b19d --- /dev/null +++ b/drivers/video/backlight/rave-sp-backlight.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/* + * LCD Backlight driver for RAVE SP + * + * Copyright (C) 2018 Zodiac Inflight Innovations + * + */ + +#include <linux/backlight.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mfd/rave-sp.h> +#include <linux/platform_device.h> + +#define RAVE_SP_BACKLIGHT_LCD_EN BIT(7) + +static int rave_sp_backlight_update_status(struct backlight_device *bd) +{ + const struct backlight_properties *p = &bd->props; + const u8 intensity = + (p->power == FB_BLANK_UNBLANK) ? p->brightness : 0; + struct rave_sp *sp = dev_get_drvdata(&bd->dev); + u8 cmd[] = { + [0] = RAVE_SP_CMD_SET_BACKLIGHT, + [1] = 0, + [2] = intensity ? RAVE_SP_BACKLIGHT_LCD_EN | intensity : 0, + [3] = 0, + [4] = 0, + }; + + return rave_sp_exec(sp, cmd, sizeof(cmd), NULL, 0); +} + +static const struct backlight_ops rave_sp_backlight_ops = { + .options = BL_CORE_SUSPENDRESUME, + .update_status = rave_sp_backlight_update_status, +}; + +static struct backlight_properties rave_sp_backlight_props = { + .type = BACKLIGHT_PLATFORM, + .max_brightness = 100, + .brightness = 50, +}; + +static int rave_sp_backlight_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct backlight_device *bd; + + bd = devm_backlight_device_register(dev, pdev->name, dev->parent, + dev_get_drvdata(dev->parent), + &rave_sp_backlight_ops, + &rave_sp_backlight_props); + if (IS_ERR(bd)) + return PTR_ERR(bd); + + backlight_update_status(bd); + + return 0; +} + +static const struct of_device_id rave_sp_backlight_of_match[] = { + { .compatible = "zii,rave-sp-backlight" }, + {} +}; + +static struct platform_driver rave_sp_backlight_driver = { + .probe = rave_sp_backlight_probe, + .driver = { + .name = KBUILD_MODNAME, + .of_match_table = rave_sp_backlight_of_match, + }, +}; +module_platform_driver(rave_sp_backlight_driver); + +MODULE_DEVICE_TABLE(of, rave_sp_backlight_of_match); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Andrey Vostrikov <andrey.vostrikov@cogentembedded.com>"); +MODULE_AUTHOR("Nikita Yushchenko <nikita.yoush@cogentembedded.com>"); +MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>"); +MODULE_DESCRIPTION("RAVE SP Backlight driver"); diff --git a/drivers/video/backlight/tps65217_bl.c b/drivers/video/backlight/tps65217_bl.c index 380917c86276..762e3feed097 100644 --- a/drivers/video/backlight/tps65217_bl.c +++ b/drivers/video/backlight/tps65217_bl.c @@ -184,11 +184,11 @@ static struct tps65217_bl_pdata * tps65217_bl_parse_dt(struct platform_device *pdev) { struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent); - struct device_node *node = of_node_get(tps->dev->of_node); + struct device_node *node; struct tps65217_bl_pdata *pdata, *err; u32 val; - node = of_find_node_by_name(node, "backlight"); + node = of_get_child_by_name(tps->dev->of_node, "backlight"); if (!node) return ERR_PTR(-ENODEV); diff --git a/drivers/video/console/sticore.c b/drivers/video/console/sticore.c index 08b822656846..ff45dca3ee46 100644 --- a/drivers/video/console/sticore.c +++ b/drivers/video/console/sticore.c @@ -649,7 +649,7 @@ static void *sti_bmode_font_raw(struct sti_cooked_font *f) unsigned char *n, *p, *q; int size = f->raw->bytes_per_char*256+sizeof(struct sti_rom_font); - n = kzalloc(4*size, STI_LOWMEM); + n = kcalloc(4, size, STI_LOWMEM); if (!n) return NULL; p = n + 3; diff --git a/drivers/video/fbdev/au1100fb.c b/drivers/video/fbdev/au1100fb.c index 7c9a672e9811..d555a78df5c6 100644 --- a/drivers/video/fbdev/au1100fb.c +++ b/drivers/video/fbdev/au1100fb.c @@ -501,7 +501,7 @@ static int au1100fb_drv_probe(struct platform_device *dev) fbdev->info.fix = au1100fb_fix; fbdev->info.pseudo_palette = - devm_kzalloc(&dev->dev, sizeof(u32) * 16, GFP_KERNEL); + devm_kcalloc(&dev->dev, 16, sizeof(u32), GFP_KERNEL); if (!fbdev->info.pseudo_palette) return -ENOMEM; diff --git a/drivers/video/fbdev/broadsheetfb.c b/drivers/video/fbdev/broadsheetfb.c index 9f9a7bef1ff6..d6ba348deb9f 100644 --- a/drivers/video/fbdev/broadsheetfb.c +++ b/drivers/video/fbdev/broadsheetfb.c @@ -617,7 +617,7 @@ static int broadsheet_spiflash_rewrite_sector(struct broadsheetfb_par *par, int tail_start_addr; int start_sector_addr; - sector_buffer = kzalloc(sizeof(char)*sector_size, GFP_KERNEL); + sector_buffer = kzalloc(sector_size, GFP_KERNEL); if (!sector_buffer) return -ENOMEM; diff --git a/drivers/video/fbdev/core/bitblit.c b/drivers/video/fbdev/core/bitblit.c index 790900d646c0..ca935c09a261 100644 --- a/drivers/video/fbdev/core/bitblit.c +++ b/drivers/video/fbdev/core/bitblit.c @@ -269,7 +269,7 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, int mode, if (attribute) { u8 *dst; - dst = kmalloc(w * vc->vc_font.height, GFP_ATOMIC); + dst = kmalloc_array(w, vc->vc_font.height, GFP_ATOMIC); if (!dst) return; kfree(ops->cursor_data); @@ -312,7 +312,7 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, int mode, vc->vc_cursor_type != ops->p->cursor_shape || ops->cursor_state.mask == NULL || ops->cursor_reset) { - char *mask = kmalloc(w*vc->vc_font.height, GFP_ATOMIC); + char *mask = kmalloc_array(w, vc->vc_font.height, GFP_ATOMIC); int cur_height, size, i = 0; u8 msk = 0xff; diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index 3e330e0f56ed..c910e74d46ff 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -591,7 +591,8 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, if (scr_readw(r) != vc->vc_video_erase_char) break; if (r != q && new_rows >= rows + logo_lines) { - save = kmalloc(logo_lines * new_cols * 2, GFP_KERNEL); + save = kmalloc(array3_size(logo_lines, new_cols, 2), + GFP_KERNEL); if (save) { int i = cols < new_cols ? cols : new_cols; scr_memsetw(save, erase, logo_lines * new_cols * 2); diff --git a/drivers/video/fbdev/core/fbcon_ccw.c b/drivers/video/fbdev/core/fbcon_ccw.c index 37a8b0b22566..dfa9a8aa4509 100644 --- a/drivers/video/fbdev/core/fbcon_ccw.c +++ b/drivers/video/fbdev/core/fbcon_ccw.c @@ -258,7 +258,7 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, int mode, if (attribute) { u8 *dst; - dst = kmalloc(w * vc->vc_font.width, GFP_ATOMIC); + dst = kmalloc_array(w, vc->vc_font.width, GFP_ATOMIC); if (!dst) return; kfree(ops->cursor_data); @@ -304,14 +304,15 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, int mode, vc->vc_cursor_type != ops->p->cursor_shape || ops->cursor_state.mask == NULL || ops->cursor_reset) { - char *tmp, *mask = kmalloc(w*vc->vc_font.width, GFP_ATOMIC); + char *tmp, *mask = kmalloc_array(w, vc->vc_font.width, + GFP_ATOMIC); int cur_height, size, i = 0; int width = (vc->vc_font.width + 7)/8; if (!mask) return; - tmp = kmalloc(width * vc->vc_font.height, GFP_ATOMIC); + tmp = kmalloc_array(width, vc->vc_font.height, GFP_ATOMIC); if (!tmp) { kfree(mask); diff --git a/drivers/video/fbdev/core/fbcon_cw.c b/drivers/video/fbdev/core/fbcon_cw.c index 1888f8c866e8..ce08251bfd38 100644 --- a/drivers/video/fbdev/core/fbcon_cw.c +++ b/drivers/video/fbdev/core/fbcon_cw.c @@ -241,7 +241,7 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode, if (attribute) { u8 *dst; - dst = kmalloc(w * vc->vc_font.width, GFP_ATOMIC); + dst = kmalloc_array(w, vc->vc_font.width, GFP_ATOMIC); if (!dst) return; kfree(ops->cursor_data); @@ -287,14 +287,15 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode, vc->vc_cursor_type != ops->p->cursor_shape || ops->cursor_state.mask == NULL || ops->cursor_reset) { - char *tmp, *mask = kmalloc(w*vc->vc_font.width, GFP_ATOMIC); + char *tmp, *mask = kmalloc_array(w, vc->vc_font.width, + GFP_ATOMIC); int cur_height, size, i = 0; int width = (vc->vc_font.width + 7)/8; if (!mask) return; - tmp = kmalloc(width * vc->vc_font.height, GFP_ATOMIC); + tmp = kmalloc_array(width, vc->vc_font.height, GFP_ATOMIC); if (!tmp) { kfree(mask); diff --git a/drivers/video/fbdev/core/fbcon_rotate.c b/drivers/video/fbdev/core/fbcon_rotate.c index 8a51e4d95cc5..c0d445294aa7 100644 --- a/drivers/video/fbdev/core/fbcon_rotate.c +++ b/drivers/video/fbdev/core/fbcon_rotate.c @@ -46,7 +46,7 @@ static int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc) info->fbops->fb_sync(info); if (ops->fd_size < d_cellsize * len) { - dst = kmalloc(d_cellsize * len, GFP_KERNEL); + dst = kmalloc_array(len, d_cellsize, GFP_KERNEL); if (dst == NULL) { err = -ENOMEM; diff --git a/drivers/video/fbdev/core/fbcon_ud.c b/drivers/video/fbdev/core/fbcon_ud.c index f98eee263597..1936afc78fec 100644 --- a/drivers/video/fbdev/core/fbcon_ud.c +++ b/drivers/video/fbdev/core/fbcon_ud.c @@ -289,7 +289,7 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, int mode, if (attribute) { u8 *dst; - dst = kmalloc(w * vc->vc_font.height, GFP_ATOMIC); + dst = kmalloc_array(w, vc->vc_font.height, GFP_ATOMIC); if (!dst) return; kfree(ops->cursor_data); @@ -335,7 +335,7 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, int mode, vc->vc_cursor_type != ops->p->cursor_shape || ops->cursor_state.mask == NULL || ops->cursor_reset) { - char *mask = kmalloc(w*vc->vc_font.height, GFP_ATOMIC); + char *mask = kmalloc_array(w, vc->vc_font.height, GFP_ATOMIC); int cur_height, size, i = 0; u8 msk = 0xff; diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index 924d0730ffe2..609438d2465b 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -489,7 +489,8 @@ static int fb_show_logo_line(struct fb_info *info, int rotate, } if (fb_logo.depth <= 4) { - logo_new = kmalloc(logo->width * logo->height, GFP_KERNEL); + logo_new = kmalloc_array(logo->width, logo->height, + GFP_KERNEL); if (logo_new == NULL) { kfree(palette); if (saved_pseudo_palette) @@ -506,8 +507,8 @@ static int fb_show_logo_line(struct fb_info *info, int rotate, image.height = logo->height; if (rotate) { - logo_rotate = kmalloc(logo->width * - logo->height, GFP_KERNEL); + logo_rotate = kmalloc_array(logo->width, logo->height, + GFP_KERNEL); if (logo_rotate) fb_rotate_logo(info, logo_rotate, &image, rotate); } diff --git a/drivers/video/fbdev/core/fbmon.c b/drivers/video/fbdev/core/fbmon.c index 2b2d67328514..852d86c1c527 100644 --- a/drivers/video/fbdev/core/fbmon.c +++ b/drivers/video/fbdev/core/fbmon.c @@ -620,7 +620,7 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize, int num = 0, i, first = 1; int ver, rev; - mode = kzalloc(50 * sizeof(struct fb_videomode), GFP_KERNEL); + mode = kcalloc(50, sizeof(struct fb_videomode), GFP_KERNEL); if (mode == NULL) return NULL; @@ -671,7 +671,7 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize, } *dbsize = num; - m = kmalloc(num * sizeof(struct fb_videomode), GFP_KERNEL); + m = kmalloc_array(num, sizeof(struct fb_videomode), GFP_KERNEL); if (!m) return mode; memmove(m, mode, num * sizeof(struct fb_videomode)); @@ -1055,8 +1055,9 @@ void fb_edid_add_monspecs(unsigned char *edid, struct fb_monspecs *specs) if (!(num + svd_n)) return; - m = kzalloc((specs->modedb_len + num + svd_n) * - sizeof(struct fb_videomode), GFP_KERNEL); + m = kcalloc(specs->modedb_len + num + svd_n, + sizeof(struct fb_videomode), + GFP_KERNEL); if (!m) return; diff --git a/drivers/video/fbdev/imxfb.c b/drivers/video/fbdev/imxfb.c index ba82f97fb42b..c4eb8661f751 100644 --- a/drivers/video/fbdev/imxfb.c +++ b/drivers/video/fbdev/imxfb.c @@ -662,7 +662,7 @@ static int imxfb_init_fbinfo(struct platform_device *pdev) pr_debug("%s\n",__func__); - info->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL); + info->pseudo_palette = kmalloc_array(16, sizeof(u32), GFP_KERNEL); if (!info->pseudo_palette) return -ENOMEM; diff --git a/drivers/video/fbdev/mb862xx/mb862xxfb_accel.c b/drivers/video/fbdev/mb862xx/mb862xxfb_accel.c index fe92eed6da70..8dd296d257dd 100644 --- a/drivers/video/fbdev/mb862xx/mb862xxfb_accel.c +++ b/drivers/video/fbdev/mb862xx/mb862xxfb_accel.c @@ -245,7 +245,7 @@ static void mb86290fb_imageblit(struct fb_info *info, return; } - cmd = kmalloc(cmdlen * 4, GFP_DMA); + cmd = kmalloc_array(cmdlen, 4, GFP_DMA); if (!cmd) return cfb_imageblit(info, image); cmdfn(cmd, step, dx, dy, width, height, fgcolor, bgcolor, image, info); diff --git a/drivers/video/fbdev/mmp/fb/mmpfb.c b/drivers/video/fbdev/mmp/fb/mmpfb.c index 92279e02dd94..f27697e07c55 100644 --- a/drivers/video/fbdev/mmp/fb/mmpfb.c +++ b/drivers/video/fbdev/mmp/fb/mmpfb.c @@ -493,8 +493,8 @@ static int modes_setup(struct mmpfb_info *fbi) return 0; } /* put videomode list to info structure */ - videomodes = kzalloc(sizeof(struct fb_videomode) * videomode_num, - GFP_KERNEL); + videomodes = kcalloc(videomode_num, sizeof(struct fb_videomode), + GFP_KERNEL); if (!videomodes) { dev_err(fbi->dev, "can't malloc video modes\n"); return -ENOMEM; diff --git a/drivers/video/fbdev/mxsfb.c b/drivers/video/fbdev/mxsfb.c index 246bea3a7d9b..12c8bd1d24d5 100644 --- a/drivers/video/fbdev/mxsfb.c +++ b/drivers/video/fbdev/mxsfb.c @@ -931,7 +931,7 @@ static int mxsfb_probe(struct platform_device *pdev) if (IS_ERR(host->reg_lcd)) host->reg_lcd = NULL; - fb_info->pseudo_palette = devm_kzalloc(&pdev->dev, sizeof(u32) * 16, + fb_info->pseudo_palette = devm_kcalloc(&pdev->dev, 16, sizeof(u32), GFP_KERNEL); if (!fb_info->pseudo_palette) { ret = -ENOMEM; diff --git a/drivers/video/fbdev/nvidia/nvidia.c b/drivers/video/fbdev/nvidia/nvidia.c index 418a2d0d06a9..2e50120bcfae 100644 --- a/drivers/video/fbdev/nvidia/nvidia.c +++ b/drivers/video/fbdev/nvidia/nvidia.c @@ -566,7 +566,7 @@ static int nvidiafb_cursor(struct fb_info *info, struct fb_cursor *cursor) u8 *msk = (u8 *) cursor->mask; u8 *src; - src = kmalloc(s_pitch * cursor->image.height, GFP_ATOMIC); + src = kmalloc_array(s_pitch, cursor->image.height, GFP_ATOMIC); if (src) { switch (cursor->rop) { diff --git a/drivers/video/fbdev/omap2/omapfb/dss/manager.c b/drivers/video/fbdev/omap2/omapfb/dss/manager.c index 69f86d2cc274..d21c641e1f3c 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/manager.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/manager.c @@ -42,8 +42,8 @@ int dss_init_overlay_managers(void) num_managers = dss_feat_get_num_mgrs(); - managers = kzalloc(sizeof(struct omap_overlay_manager) * num_managers, - GFP_KERNEL); + managers = kcalloc(num_managers, sizeof(struct omap_overlay_manager), + GFP_KERNEL); BUG_ON(managers == NULL); diff --git a/drivers/video/fbdev/omap2/omapfb/dss/overlay.c b/drivers/video/fbdev/omap2/omapfb/dss/overlay.c index d6c5d75d2ef8..be17a4785a5e 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/overlay.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/overlay.c @@ -59,8 +59,8 @@ void dss_init_overlays(struct platform_device *pdev) num_overlays = dss_feat_get_num_ovls(); - overlays = kzalloc(sizeof(struct omap_overlay) * num_overlays, - GFP_KERNEL); + overlays = kcalloc(num_overlays, sizeof(struct omap_overlay), + GFP_KERNEL); BUG_ON(overlays == NULL); diff --git a/drivers/video/fbdev/omap2/omapfb/vrfb.c b/drivers/video/fbdev/omap2/omapfb/vrfb.c index f346b02eee1d..f355ecfac3b1 100644 --- a/drivers/video/fbdev/omap2/omapfb/vrfb.c +++ b/drivers/video/fbdev/omap2/omapfb/vrfb.c @@ -359,8 +359,8 @@ static int __init vrfb_probe(struct platform_device *pdev) num_ctxs = pdev->num_resources - 1; - ctxs = devm_kzalloc(&pdev->dev, - sizeof(struct vrfb_ctx) * num_ctxs, + ctxs = devm_kcalloc(&pdev->dev, + num_ctxs, sizeof(struct vrfb_ctx), GFP_KERNEL); if (!ctxs) diff --git a/drivers/video/fbdev/pvr2fb.c b/drivers/video/fbdev/pvr2fb.c index a582d3ae7ac1..8a53d1de611d 100644 --- a/drivers/video/fbdev/pvr2fb.c +++ b/drivers/video/fbdev/pvr2fb.c @@ -682,7 +682,7 @@ static ssize_t pvr2fb_write(struct fb_info *info, const char *buf, nr_pages = (count + PAGE_SIZE - 1) >> PAGE_SHIFT; - pages = kmalloc(nr_pages * sizeof(struct page *), GFP_KERNEL); + pages = kmalloc_array(nr_pages, sizeof(struct page *), GFP_KERNEL); if (!pages) return -ENOMEM; diff --git a/drivers/video/fbdev/riva/fbdev.c b/drivers/video/fbdev/riva/fbdev.c index ff8282374f37..cc242ba057d3 100644 --- a/drivers/video/fbdev/riva/fbdev.c +++ b/drivers/video/fbdev/riva/fbdev.c @@ -1615,7 +1615,7 @@ static int rivafb_cursor(struct fb_info *info, struct fb_cursor *cursor) u8 *msk = (u8 *) cursor->mask; u8 *src; - src = kmalloc(s_pitch * cursor->image.height, GFP_ATOMIC); + src = kmalloc_array(s_pitch, cursor->image.height, GFP_ATOMIC); if (src) { switch (cursor->rop) { diff --git a/drivers/video/fbdev/uvesafb.c b/drivers/video/fbdev/uvesafb.c index 73676eb0244a..440a6636d8f0 100644 --- a/drivers/video/fbdev/uvesafb.c +++ b/drivers/video/fbdev/uvesafb.c @@ -486,8 +486,9 @@ static int uvesafb_vbe_getmodes(struct uvesafb_ktask *task, mode++; } - par->vbe_modes = kzalloc(sizeof(struct vbe_mode_ib) * - par->vbe_modes_cnt, GFP_KERNEL); + par->vbe_modes = kcalloc(par->vbe_modes_cnt, + sizeof(struct vbe_mode_ib), + GFP_KERNEL); if (!par->vbe_modes) return -ENOMEM; @@ -858,7 +859,7 @@ static int uvesafb_vbe_init_mode(struct fb_info *info) * Convert the modelist into a modedb so that we can use it with * fb_find_mode(). */ - mode = kzalloc(i * sizeof(*mode), GFP_KERNEL); + mode = kcalloc(i, sizeof(*mode), GFP_KERNEL); if (mode) { i = 0; list_for_each(pos, &info->modelist) { @@ -1044,7 +1045,8 @@ static int uvesafb_setcmap(struct fb_cmap *cmap, struct fb_info *info) info->cmap.len || cmap->start < info->cmap.start) return -EINVAL; - entries = kmalloc(sizeof(*entries) * cmap->len, GFP_KERNEL); + entries = kmalloc_array(cmap->len, sizeof(*entries), + GFP_KERNEL); if (!entries) return -ENOMEM; diff --git a/drivers/video/fbdev/via/viafbdev.c b/drivers/video/fbdev/via/viafbdev.c index 9b45125988fb..52f577b0669b 100644 --- a/drivers/video/fbdev/via/viafbdev.c +++ b/drivers/video/fbdev/via/viafbdev.c @@ -596,7 +596,8 @@ static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg) break; case VIAFB_GET_GAMMA_LUT: - viafb_gamma_table = kmalloc(256 * sizeof(u32), GFP_KERNEL); + viafb_gamma_table = kmalloc_array(256, sizeof(u32), + GFP_KERNEL); if (!viafb_gamma_table) return -ENOMEM; viafb_get_gamma_table(viafb_gamma_table); diff --git a/drivers/video/fbdev/w100fb.c b/drivers/video/fbdev/w100fb.c index 035ff6e02894..696106ecdff0 100644 --- a/drivers/video/fbdev/w100fb.c +++ b/drivers/video/fbdev/w100fb.c @@ -693,7 +693,8 @@ int w100fb_probe(struct platform_device *pdev) goto out; } - info->pseudo_palette = kmalloc(sizeof (u32) * MAX_PALETTES, GFP_KERNEL); + info->pseudo_palette = kmalloc_array(MAX_PALETTES, sizeof(u32), + GFP_KERNEL); if (!info->pseudo_palette) { err = -ENOMEM; goto out; diff --git a/drivers/video/fbdev/xen-fbfront.c b/drivers/video/fbdev/xen-fbfront.c index 46f63960fa9e..6a4bbc9e1fb0 100644 --- a/drivers/video/fbdev/xen-fbfront.c +++ b/drivers/video/fbdev/xen-fbfront.c @@ -412,7 +412,7 @@ static int xenfb_probe(struct xenbus_device *dev, info->nr_pages = (fb_size + PAGE_SIZE - 1) >> PAGE_SHIFT; - info->gfns = vmalloc(sizeof(unsigned long) * info->nr_pages); + info->gfns = vmalloc(array_size(sizeof(unsigned long), info->nr_pages)); if (!info->gfns) goto error_nomem; diff --git a/drivers/video/of_display_timing.c b/drivers/video/of_display_timing.c index 83b8963c9657..5244e93ceafc 100644 --- a/drivers/video/of_display_timing.c +++ b/drivers/video/of_display_timing.c @@ -181,8 +181,9 @@ struct display_timings *of_get_display_timings(const struct device_node *np) goto entryfail; } - disp->timings = kzalloc(sizeof(struct display_timing *) * - disp->num_timings, GFP_KERNEL); + disp->timings = kcalloc(disp->num_timings, + sizeof(struct display_timing *), + GFP_KERNEL); if (!disp->timings) { pr_err("%pOF: could not allocate timings array\n", np); goto entryfail; diff --git a/drivers/virt/fsl_hypervisor.c b/drivers/virt/fsl_hypervisor.c index 4e05d7f711fe..8ba726e600e9 100644 --- a/drivers/virt/fsl_hypervisor.c +++ b/drivers/virt/fsl_hypervisor.c @@ -223,7 +223,7 @@ static long ioctl_memcpy(struct fsl_hv_ioctl_memcpy __user *p) * 'pages' is an array of struct page pointers that's initialized by * get_user_pages(). */ - pages = kzalloc(num_pages * sizeof(struct page *), GFP_KERNEL); + pages = kcalloc(num_pages, sizeof(struct page *), GFP_KERNEL); if (!pages) { pr_debug("fsl-hv: could not allocate page list\n"); return -ENOMEM; diff --git a/drivers/virt/vboxguest/vboxguest_core.c b/drivers/virt/vboxguest/vboxguest_core.c index 2f3856a95856..3093655c7b92 100644 --- a/drivers/virt/vboxguest/vboxguest_core.c +++ b/drivers/virt/vboxguest/vboxguest_core.c @@ -69,7 +69,7 @@ static void vbg_guest_mappings_init(struct vbg_dev *gdev) /* Add 4M so that we can align the vmap to 4MiB as the host requires. */ size = PAGE_ALIGN(req->hypervisor_size) + SZ_4M; - pages = kmalloc(sizeof(*pages) * (size >> PAGE_SHIFT), GFP_KERNEL); + pages = kmalloc_array(size >> PAGE_SHIFT, sizeof(*pages), GFP_KERNEL); if (!pages) goto out; @@ -262,8 +262,9 @@ static int vbg_balloon_inflate(struct vbg_dev *gdev, u32 chunk_idx) struct page **pages; int i, rc, ret; - pages = kmalloc(sizeof(*pages) * VMMDEV_MEMORY_BALLOON_CHUNK_PAGES, - GFP_KERNEL | __GFP_NOWARN); + pages = kmalloc_array(VMMDEV_MEMORY_BALLOON_CHUNK_PAGES, + sizeof(*pages), + GFP_KERNEL | __GFP_NOWARN); if (!pages) return -ENOMEM; diff --git a/drivers/virtio/virtio_pci_common.c b/drivers/virtio/virtio_pci_common.c index 48d4d1cf1cb6..705aebd74e56 100644 --- a/drivers/virtio/virtio_pci_common.c +++ b/drivers/virtio/virtio_pci_common.c @@ -113,12 +113,13 @@ static int vp_request_msix_vectors(struct virtio_device *vdev, int nvectors, vp_dev->msix_vectors = nvectors; - vp_dev->msix_names = kmalloc(nvectors * sizeof *vp_dev->msix_names, - GFP_KERNEL); + vp_dev->msix_names = kmalloc_array(nvectors, + sizeof(*vp_dev->msix_names), + GFP_KERNEL); if (!vp_dev->msix_names) goto error; vp_dev->msix_affinity_masks - = kzalloc(nvectors * sizeof *vp_dev->msix_affinity_masks, + = kcalloc(nvectors, sizeof(*vp_dev->msix_affinity_masks), GFP_KERNEL); if (!vp_dev->msix_affinity_masks) goto error; @@ -577,6 +578,8 @@ static void virtio_pci_remove(struct pci_dev *pci_dev) struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev); struct device *dev = get_device(&vp_dev->vdev.dev); + pci_disable_sriov(pci_dev); + unregister_virtio_device(&vp_dev->vdev); if (vp_dev->ioaddr) @@ -588,6 +591,33 @@ static void virtio_pci_remove(struct pci_dev *pci_dev) put_device(dev); } +static int virtio_pci_sriov_configure(struct pci_dev *pci_dev, int num_vfs) +{ + struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev); + struct virtio_device *vdev = &vp_dev->vdev; + int ret; + + if (!(vdev->config->get_status(vdev) & VIRTIO_CONFIG_S_DRIVER_OK)) + return -EBUSY; + + if (!__virtio_test_bit(vdev, VIRTIO_F_SR_IOV)) + return -EINVAL; + + if (pci_vfs_assigned(pci_dev)) + return -EPERM; + + if (num_vfs == 0) { + pci_disable_sriov(pci_dev); + return 0; + } + + ret = pci_enable_sriov(pci_dev, num_vfs); + if (ret < 0) + return ret; + + return num_vfs; +} + static struct pci_driver virtio_pci_driver = { .name = "virtio-pci", .id_table = virtio_pci_id_table, @@ -596,6 +626,7 @@ static struct pci_driver virtio_pci_driver = { #ifdef CONFIG_PM_SLEEP .driver.pm = &virtio_pci_pm_ops, #endif + .sriov_configure = virtio_pci_sriov_configure, }; module_pci_driver(virtio_pci_driver); diff --git a/drivers/virtio/virtio_pci_modern.c b/drivers/virtio/virtio_pci_modern.c index 2555d80f6eec..07571daccfec 100644 --- a/drivers/virtio/virtio_pci_modern.c +++ b/drivers/virtio/virtio_pci_modern.c @@ -153,14 +153,28 @@ static u64 vp_get_features(struct virtio_device *vdev) return features; } +static void vp_transport_features(struct virtio_device *vdev, u64 features) +{ + struct virtio_pci_device *vp_dev = to_vp_device(vdev); + struct pci_dev *pci_dev = vp_dev->pci_dev; + + if ((features & BIT_ULL(VIRTIO_F_SR_IOV)) && + pci_find_ext_capability(pci_dev, PCI_EXT_CAP_ID_SRIOV)) + __virtio_set_bit(vdev, VIRTIO_F_SR_IOV); +} + /* virtio config->finalize_features() implementation */ static int vp_finalize_features(struct virtio_device *vdev) { struct virtio_pci_device *vp_dev = to_vp_device(vdev); + u64 features = vdev->features; /* Give virtio_ring a chance to accept features. */ vring_transport_features(vdev); + /* Give virtio_pci a chance to accept features. */ + vp_transport_features(vdev, features); + if (!__virtio_test_bit(vdev, VIRTIO_F_VERSION_1)) { dev_err(&vdev->dev, "virtio: device uses modern interface " "but does not have VIRTIO_F_VERSION_1\n"); diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index 21d464a29cf8..814b395007b2 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -247,7 +247,7 @@ static struct vring_desc *alloc_indirect(struct virtqueue *_vq, */ gfp &= ~__GFP_HIGHMEM; - desc = kmalloc(total_sg * sizeof(struct vring_desc), gfp); + desc = kmalloc_array(total_sg, sizeof(struct vring_desc), gfp); if (!desc) return NULL; diff --git a/drivers/watchdog/cadence_wdt.c b/drivers/watchdog/cadence_wdt.c index 3ec1f418837d..c3924356d173 100644 --- a/drivers/watchdog/cadence_wdt.c +++ b/drivers/watchdog/cadence_wdt.c @@ -418,8 +418,7 @@ static void cdns_wdt_shutdown(struct platform_device *pdev) */ static int __maybe_unused cdns_wdt_suspend(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct cdns_wdt *wdt = platform_get_drvdata(pdev); + struct cdns_wdt *wdt = dev_get_drvdata(dev); if (watchdog_active(&wdt->cdns_wdt_device)) { cdns_wdt_stop(&wdt->cdns_wdt_device); @@ -438,8 +437,7 @@ static int __maybe_unused cdns_wdt_suspend(struct device *dev) static int __maybe_unused cdns_wdt_resume(struct device *dev) { int ret; - struct platform_device *pdev = to_platform_device(dev); - struct cdns_wdt *wdt = platform_get_drvdata(pdev); + struct cdns_wdt *wdt = dev_get_drvdata(dev); if (watchdog_active(&wdt->cdns_wdt_device)) { ret = clk_prepare_enable(wdt->clk); diff --git a/drivers/watchdog/da9062_wdt.c b/drivers/watchdog/da9062_wdt.c index a001782bbfdb..fe169d8e1fb2 100644 --- a/drivers/watchdog/da9062_wdt.c +++ b/drivers/watchdog/da9062_wdt.c @@ -30,14 +30,8 @@ static const unsigned int wdt_timeout[] = { 0, 2, 4, 8, 16, 32, 65, 131 }; struct da9062_watchdog { struct da9062 *hw; struct watchdog_device wdtdev; - unsigned long j_time_stamp; }; -static void da9062_set_window_start(struct da9062_watchdog *wdt) -{ - wdt->j_time_stamp = jiffies; -} - static unsigned int da9062_wdt_timeout_to_sel(unsigned int secs) { unsigned int i; @@ -59,8 +53,6 @@ static int da9062_reset_watchdog_timer(struct da9062_watchdog *wdt) DA9062AA_WATCHDOG_MASK, DA9062AA_WATCHDOG_MASK); - da9062_set_window_start(wdt); - return ret; } @@ -232,8 +224,6 @@ static int da9062_wdt_probe(struct platform_device *pdev) return ret; } - da9062_set_window_start(wdt); - return da9062_wdt_ping(&wdt->wdtdev); } diff --git a/drivers/watchdog/da9063_wdt.c b/drivers/watchdog/da9063_wdt.c index b17ac1bb1f28..384dca16af8b 100644 --- a/drivers/watchdog/da9063_wdt.c +++ b/drivers/watchdog/da9063_wdt.c @@ -45,20 +45,56 @@ static unsigned int da9063_wdt_timeout_to_sel(unsigned int secs) return DA9063_TWDSCALE_MAX; } -static int _da9063_wdt_set_timeout(struct da9063 *da9063, unsigned int regval) +/* + * Return 0 if watchdog is disabled, else non zero. + */ +static unsigned int da9063_wdt_is_running(struct da9063 *da9063) +{ + unsigned int val; + + regmap_read(da9063->regmap, DA9063_REG_CONTROL_D, &val); + + return val & DA9063_TWDSCALE_MASK; +} + +static int da9063_wdt_disable_timer(struct da9063 *da9063) { return regmap_update_bits(da9063->regmap, DA9063_REG_CONTROL_D, + DA9063_TWDSCALE_MASK, + DA9063_TWDSCALE_DISABLE); +} + +static int +da9063_wdt_update_timeout(struct da9063 *da9063, unsigned int timeout) +{ + unsigned int regval; + int ret; + + /* + * The watchdog triggers a reboot if a timeout value is already + * programmed because the timeout value combines two functions + * in one: indicating the counter limit and starting the watchdog. + * The watchdog must be disabled to be able to change the timeout + * value if the watchdog is already running. Then we can set the + * new timeout value which enables the watchdog again. + */ + ret = da9063_wdt_disable_timer(da9063); + if (ret) + return ret; + + usleep_range(150, 300); + regval = da9063_wdt_timeout_to_sel(timeout); + + return regmap_update_bits(da9063->regmap, DA9063_REG_CONTROL_D, DA9063_TWDSCALE_MASK, regval); } static int da9063_wdt_start(struct watchdog_device *wdd) { struct da9063 *da9063 = watchdog_get_drvdata(wdd); - unsigned int selector; int ret; - selector = da9063_wdt_timeout_to_sel(wdd->timeout); - ret = _da9063_wdt_set_timeout(da9063, selector); + ret = da9063_wdt_update_timeout(da9063, wdd->timeout); if (ret) dev_err(da9063->dev, "Watchdog failed to start (err = %d)\n", ret); @@ -71,8 +107,7 @@ static int da9063_wdt_stop(struct watchdog_device *wdd) struct da9063 *da9063 = watchdog_get_drvdata(wdd); int ret; - ret = regmap_update_bits(da9063->regmap, DA9063_REG_CONTROL_D, - DA9063_TWDSCALE_MASK, DA9063_TWDSCALE_DISABLE); + ret = da9063_wdt_disable_timer(da9063); if (ret) dev_alert(da9063->dev, "Watchdog failed to stop (err = %d)\n", ret); @@ -98,16 +133,26 @@ static int da9063_wdt_set_timeout(struct watchdog_device *wdd, unsigned int timeout) { struct da9063 *da9063 = watchdog_get_drvdata(wdd); - unsigned int selector; - int ret; + int ret = 0; + + /* + * There are two cases when a set_timeout() will be called: + * 1. The watchdog is off and someone wants to set the timeout for the + * further use. + * 2. The watchdog is already running and a new timeout value should be + * set. + * + * The watchdog can't store a timeout value not equal zero without + * enabling the watchdog, so the timeout must be buffered by the driver. + */ + if (watchdog_active(wdd)) + ret = da9063_wdt_update_timeout(da9063, timeout); - selector = da9063_wdt_timeout_to_sel(timeout); - ret = _da9063_wdt_set_timeout(da9063, selector); if (ret) dev_err(da9063->dev, "Failed to set watchdog timeout (err = %d)\n", ret); else - wdd->timeout = wdt_timeout[selector]; + wdd->timeout = wdt_timeout[da9063_wdt_timeout_to_sel(timeout)]; return ret; } @@ -171,6 +216,12 @@ static int da9063_wdt_probe(struct platform_device *pdev) watchdog_set_drvdata(wdd, da9063); + /* Change the timeout to the default value if the watchdog is running */ + if (da9063_wdt_is_running(da9063)) { + da9063_wdt_update_timeout(da9063, DA9063_WDG_TIMEOUT); + set_bit(WDOG_HW_RUNNING, &wdd->status); + } + return devm_watchdog_register_device(&pdev->dev, wdd); } diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index a43ab2cecca2..9dc62a461451 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -159,7 +159,7 @@ static int hpwdt_pretimeout(unsigned int ulReason, struct pt_regs *regs) "3. OA Forward Progress Log\n" "4. iLO Event Log"; - if (ilo5 && ulReason == NMI_UNKNOWN && mynmi) + if (ilo5 && ulReason == NMI_UNKNOWN && !mynmi) return NMI_DONE; if (ilo5 && !pretimeout) diff --git a/drivers/watchdog/jz4740_wdt.c b/drivers/watchdog/jz4740_wdt.c index aafbeb96561b..ec4d99a830ba 100644 --- a/drivers/watchdog/jz4740_wdt.c +++ b/drivers/watchdog/jz4740_wdt.c @@ -124,12 +124,20 @@ static int jz4740_wdt_stop(struct watchdog_device *wdt_dev) { struct jz4740_wdt_drvdata *drvdata = watchdog_get_drvdata(wdt_dev); - jz4740_timer_disable_watchdog(); writeb(0x0, drvdata->base + JZ_REG_WDT_COUNTER_ENABLE); + jz4740_timer_disable_watchdog(); return 0; } +static int jz4740_wdt_restart(struct watchdog_device *wdt_dev, + unsigned long action, void *data) +{ + wdt_dev->timeout = 0; + jz4740_wdt_start(wdt_dev); + return 0; +} + static const struct watchdog_info jz4740_wdt_info = { .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, .identity = "jz4740 Watchdog", @@ -141,6 +149,7 @@ static const struct watchdog_ops jz4740_wdt_ops = { .stop = jz4740_wdt_stop, .ping = jz4740_wdt_ping, .set_timeout = jz4740_wdt_set_timeout, + .restart = jz4740_wdt_restart, }; #ifdef CONFIG_OF @@ -179,45 +188,26 @@ static int jz4740_wdt_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); drvdata->base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(drvdata->base)) { - ret = PTR_ERR(drvdata->base); - goto err_out; - } + if (IS_ERR(drvdata->base)) + return PTR_ERR(drvdata->base); - drvdata->rtc_clk = clk_get(&pdev->dev, "rtc"); + drvdata->rtc_clk = devm_clk_get(&pdev->dev, "rtc"); if (IS_ERR(drvdata->rtc_clk)) { dev_err(&pdev->dev, "cannot find RTC clock\n"); - ret = PTR_ERR(drvdata->rtc_clk); - goto err_out; + return PTR_ERR(drvdata->rtc_clk); } - ret = watchdog_register_device(&drvdata->wdt); + ret = devm_watchdog_register_device(&pdev->dev, &drvdata->wdt); if (ret < 0) - goto err_disable_clk; + return ret; platform_set_drvdata(pdev, drvdata); - return 0; - -err_disable_clk: - clk_put(drvdata->rtc_clk); -err_out: - return ret; -} - -static int jz4740_wdt_remove(struct platform_device *pdev) -{ - struct jz4740_wdt_drvdata *drvdata = platform_get_drvdata(pdev); - - jz4740_wdt_stop(&drvdata->wdt); - watchdog_unregister_device(&drvdata->wdt); - clk_put(drvdata->rtc_clk); return 0; } static struct platform_driver jz4740_wdt_driver = { .probe = jz4740_wdt_probe, - .remove = jz4740_wdt_remove, .driver = { .name = "jz4740-wdt", .of_match_table = of_match_ptr(jz4740_wdt_of_matches), diff --git a/drivers/watchdog/mena21_wdt.c b/drivers/watchdog/mena21_wdt.c index 25d5d2b8cfbe..0be7f50e8ff9 100644 --- a/drivers/watchdog/mena21_wdt.c +++ b/drivers/watchdog/mena21_wdt.c @@ -31,7 +31,6 @@ enum a21_wdt_gpios { struct a21_wdt_drv { struct watchdog_device wdt; - struct mutex lock; unsigned gpios[NUM_GPIOS]; }; @@ -55,12 +54,8 @@ static int a21_wdt_start(struct watchdog_device *wdt) { struct a21_wdt_drv *drv = watchdog_get_drvdata(wdt); - mutex_lock(&drv->lock); - gpio_set_value(drv->gpios[GPIO_WD_ENAB], 1); - mutex_unlock(&drv->lock); - return 0; } @@ -68,12 +63,8 @@ static int a21_wdt_stop(struct watchdog_device *wdt) { struct a21_wdt_drv *drv = watchdog_get_drvdata(wdt); - mutex_lock(&drv->lock); - gpio_set_value(drv->gpios[GPIO_WD_ENAB], 0); - mutex_unlock(&drv->lock); - return 0; } @@ -81,14 +72,10 @@ static int a21_wdt_ping(struct watchdog_device *wdt) { struct a21_wdt_drv *drv = watchdog_get_drvdata(wdt); - mutex_lock(&drv->lock); - gpio_set_value(drv->gpios[GPIO_WD_TRIG], 0); ndelay(10); gpio_set_value(drv->gpios[GPIO_WD_TRIG], 1); - mutex_unlock(&drv->lock); - return 0; } @@ -108,8 +95,6 @@ static int a21_wdt_set_timeout(struct watchdog_device *wdt, return -EINVAL; } - mutex_lock(&drv->lock); - if (timeout == 1) gpio_set_value(drv->gpios[GPIO_WD_FAST], 1); else @@ -117,8 +102,6 @@ static int a21_wdt_set_timeout(struct watchdog_device *wdt, wdt->timeout = timeout; - mutex_unlock(&drv->lock); - return 0; } @@ -191,7 +174,6 @@ static int a21_wdt_probe(struct platform_device *pdev) return ret; } - mutex_init(&drv->lock); watchdog_init_timeout(&a21_wdt, 30, &pdev->dev); watchdog_set_nowayout(&a21_wdt, nowayout); watchdog_set_drvdata(&a21_wdt, drv); diff --git a/drivers/watchdog/of_xilinx_wdt.c b/drivers/watchdog/of_xilinx_wdt.c index 4acbe05e27bb..d3f7eb046678 100644 --- a/drivers/watchdog/of_xilinx_wdt.c +++ b/drivers/watchdog/of_xilinx_wdt.c @@ -268,8 +268,7 @@ static int xwdt_remove(struct platform_device *pdev) */ static int __maybe_unused xwdt_suspend(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct xwdt_device *xdev = platform_get_drvdata(pdev); + struct xwdt_device *xdev = dev_get_drvdata(dev); if (watchdog_active(&xdev->xilinx_wdt_wdd)) xilinx_wdt_stop(&xdev->xilinx_wdt_wdd); @@ -285,8 +284,7 @@ static int __maybe_unused xwdt_suspend(struct device *dev) */ static int __maybe_unused xwdt_resume(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct xwdt_device *xdev = platform_get_drvdata(pdev); + struct xwdt_device *xdev = dev_get_drvdata(dev); int ret = 0; if (watchdog_active(&xdev->xilinx_wdt_wdd)) diff --git a/drivers/watchdog/renesas_wdt.c b/drivers/watchdog/renesas_wdt.c index 514db5cc1595..88d81feba4e6 100644 --- a/drivers/watchdog/renesas_wdt.c +++ b/drivers/watchdog/renesas_wdt.c @@ -146,7 +146,7 @@ static const struct soc_device_attribute rwdt_quirks_match[] = { .data = (void *)1, /* needs single CPU */ }, { .soc_id = "r8a7791", - .revision = "ES[12].*", + .revision = "ES1.*", .data = (void *)1, /* needs single CPU */ }, { .soc_id = "r8a7792", diff --git a/drivers/watchdog/sp805_wdt.c b/drivers/watchdog/sp805_wdt.c index 03805bc5d67a..9849db0743a7 100644 --- a/drivers/watchdog/sp805_wdt.c +++ b/drivers/watchdog/sp805_wdt.c @@ -121,6 +121,18 @@ static unsigned int wdt_timeleft(struct watchdog_device *wdd) return div_u64(load, rate); } +static int +wdt_restart(struct watchdog_device *wdd, unsigned long mode, void *cmd) +{ + struct sp805_wdt *wdt = watchdog_get_drvdata(wdd); + + writel_relaxed(0, wdt->base + WDTCONTROL); + writel_relaxed(0, wdt->base + WDTLOAD); + writel_relaxed(INT_ENABLE | RESET_ENABLE, wdt->base + WDTCONTROL); + + return 0; +} + static int wdt_config(struct watchdog_device *wdd, bool ping) { struct sp805_wdt *wdt = watchdog_get_drvdata(wdd); @@ -197,6 +209,7 @@ static const struct watchdog_ops wdt_ops = { .ping = wdt_ping, .set_timeout = wdt_setload, .get_timeleft = wdt_timeleft, + .restart = wdt_restart, }; static int @@ -230,6 +243,7 @@ sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id) spin_lock_init(&wdt->lock); watchdog_set_nowayout(&wdt->wdd, nowayout); watchdog_set_drvdata(&wdt->wdd, wdt); + watchdog_set_restart_priority(&wdt->wdd, 128); wdt_setload(&wdt->wdd, DEFAULT_TIMEOUT); ret = watchdog_register_device(&wdt->wdd); diff --git a/drivers/watchdog/wdat_wdt.c b/drivers/watchdog/wdat_wdt.c index 0da9943d405f..56ad19608a9b 100644 --- a/drivers/watchdog/wdat_wdt.c +++ b/drivers/watchdog/wdat_wdt.c @@ -447,8 +447,7 @@ static int wdat_wdt_probe(struct platform_device *pdev) #ifdef CONFIG_PM_SLEEP static int wdat_wdt_suspend_noirq(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct wdat_wdt *wdat = platform_get_drvdata(pdev); + struct wdat_wdt *wdat = dev_get_drvdata(dev); int ret; if (!watchdog_active(&wdat->wdd)) @@ -475,8 +474,7 @@ static int wdat_wdt_suspend_noirq(struct device *dev) static int wdat_wdt_resume_noirq(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct wdat_wdt *wdat = platform_get_drvdata(pdev); + struct wdat_wdt *wdat = dev_get_drvdata(dev); int ret; if (!watchdog_active(&wdat->wdd)) diff --git a/drivers/xen/arm-device.c b/drivers/xen/arm-device.c index 85dd20e05726..3e789c77f568 100644 --- a/drivers/xen/arm-device.c +++ b/drivers/xen/arm-device.c @@ -70,9 +70,9 @@ static int xen_map_device_mmio(const struct resource *resources, if ((resource_type(r) != IORESOURCE_MEM) || (nr == 0)) continue; - gpfns = kzalloc(sizeof(xen_pfn_t) * nr, GFP_KERNEL); - idxs = kzalloc(sizeof(xen_ulong_t) * nr, GFP_KERNEL); - errs = kzalloc(sizeof(int) * nr, GFP_KERNEL); + gpfns = kcalloc(nr, sizeof(xen_pfn_t), GFP_KERNEL); + idxs = kcalloc(nr, sizeof(xen_ulong_t), GFP_KERNEL); + errs = kcalloc(nr, sizeof(int), GFP_KERNEL); if (!gpfns || !idxs || !errs) { kfree(gpfns); kfree(idxs); diff --git a/drivers/xen/evtchn.c b/drivers/xen/evtchn.c index 8cac07ab60ab..6d1a5e58968f 100644 --- a/drivers/xen/evtchn.c +++ b/drivers/xen/evtchn.c @@ -322,7 +322,7 @@ static int evtchn_resize_ring(struct per_user_data *u) else new_size = 2 * u->ring_size; - new_ring = kvmalloc(new_size * sizeof(*new_ring), GFP_KERNEL); + new_ring = kvmalloc_array(new_size, sizeof(*new_ring), GFP_KERNEL); if (!new_ring) return -ENOMEM; diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c index 27be107d6480..2473b0a9e6e4 100644 --- a/drivers/xen/grant-table.c +++ b/drivers/xen/grant-table.c @@ -1137,7 +1137,7 @@ static int gnttab_map(unsigned int start_idx, unsigned int end_idx) /* No need for kzalloc as it is initialized in following hypercall * GNTTABOP_setup_table. */ - frames = kmalloc(nr_gframes * sizeof(unsigned long), GFP_ATOMIC); + frames = kmalloc_array(nr_gframes, sizeof(unsigned long), GFP_ATOMIC); if (!frames) return -ENOMEM; @@ -1300,8 +1300,9 @@ int gnttab_init(void) max_nr_glist_frames = (max_nr_grant_frames * gnttab_interface->grefs_per_grant_frame / RPP); - gnttab_list = kmalloc(max_nr_glist_frames * sizeof(grant_ref_t *), - GFP_KERNEL); + gnttab_list = kmalloc_array(max_nr_glist_frames, + sizeof(grant_ref_t *), + GFP_KERNEL); if (gnttab_list == NULL) return -ENOMEM; diff --git a/drivers/xen/xen-pciback/pciback_ops.c b/drivers/xen/xen-pciback/pciback_ops.c index ee2c891b55c6..ea4a08b83fa0 100644 --- a/drivers/xen/xen-pciback/pciback_ops.c +++ b/drivers/xen/xen-pciback/pciback_ops.c @@ -234,7 +234,7 @@ int xen_pcibk_enable_msix(struct xen_pcibk_device *pdev, if (dev->msi_enabled || !(cmd & PCI_COMMAND_MEMORY)) return -ENXIO; - entries = kmalloc(op->value * sizeof(*entries), GFP_KERNEL); + entries = kmalloc_array(op->value, sizeof(*entries), GFP_KERNEL); if (entries == NULL) return -ENOMEM; |